Skip to content

Commit

Permalink
add is syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
ate47 committed Jul 29, 2024
1 parent 2df9087 commit a110cb9
Show file tree
Hide file tree
Showing 13 changed files with 1,299 additions and 1,018 deletions.
4 changes: 3 additions & 1 deletion grammar/gsc.g4
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,13 @@ expression8: expression8 ('<' | '<=') expression9 | expression9;
expression9: expression9 ('<<' | '>>') expression10 | expression10;
expression10: expression10 ('+' | '-') expression11 | expression11;
expression11: expression11 ('*' | '/' | '%') expression12 | expression12;
expression12: ('!' | '~') expression13 | ('++' | '--') left_value | left_value ('++' | '--') | expression13;
expression12: ('!' | '~') expression13 | ('++' | '--') left_value | left_value ('++' | '--') | is_expression | expression13;
expression13: function_call_exp | expression14;
expression14: const_expr | expression15 | left_value;
expression15: ('(' expression ')');

is_expression: expression13 'is' ('not')? (IDENTIFIER | 'true' | 'false' | 'function' | 'undefined');

function_call_exp:
function_call
| expression14 ('thread' | 'childthread' | 'threadendon' | 'builtin')? function_component '(' expression_list ')';
Expand Down
4 changes: 4 additions & 0 deletions src/acts/compiler/gscBaseVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,10 @@ class gscBaseVisitor : public gscVisitor {
return visitChildren(ctx);
}

virtual std::any visitIs_expression(gscParser::Is_expressionContext *ctx) override {
return visitChildren(ctx);
}

virtual std::any visitFunction_call_exp(gscParser::Function_call_expContext *ctx) override {
return visitChildren(ctx);
}
Expand Down
523 changes: 267 additions & 256 deletions src/acts/compiler/gscLexer.cpp

Large diffs are not rendered by default.

9 changes: 5 additions & 4 deletions src/acts/compiler/gscLexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,11 @@ class gscLexer : public antlr4::Lexer {
T__62 = 63, T__63 = 64, T__64 = 65, T__65 = 66, T__66 = 67, T__67 = 68,
T__68 = 69, T__69 = 70, T__70 = 71, T__71 = 72, T__72 = 73, T__73 = 74,
T__74 = 75, T__75 = 76, T__76 = 77, T__77 = 78, T__78 = 79, T__79 = 80,
T__80 = 81, T__81 = 82, T__82 = 83, T__83 = 84, NEWLINE = 85, WHITESPACE = 86,
INTEGER10 = 87, INTEGER16 = 88, INTEGER8 = 89, INTEGER2 = 90, FLOATVAL = 91,
BUILTIN = 92, BOOL_VALUE = 93, UNDEFINED_VALUE = 94, IDENTIFIER = 95,
STRUCT_IDENTIFIER = 96, PATH = 97, STRING = 98, HASHSTRING = 99
T__80 = 81, T__81 = 82, T__82 = 83, T__83 = 84, T__84 = 85, T__85 = 86,
T__86 = 87, T__87 = 88, NEWLINE = 89, WHITESPACE = 90, INTEGER10 = 91,
INTEGER16 = 92, INTEGER8 = 93, INTEGER2 = 94, FLOATVAL = 95, BUILTIN = 96,
BOOL_VALUE = 97, UNDEFINED_VALUE = 98, IDENTIFIER = 99, STRUCT_IDENTIFIER = 100,
PATH = 101, STRING = 102, HASHSTRING = 103
};

explicit gscLexer(antlr4::CharStream *input);
Expand Down
1,590 changes: 842 additions & 748 deletions src/acts/compiler/gscParser.cpp

Large diffs are not rendered by default.

32 changes: 25 additions & 7 deletions src/acts/compiler/gscParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,11 @@ class gscParser : public antlr4::Parser {
T__62 = 63, T__63 = 64, T__64 = 65, T__65 = 66, T__66 = 67, T__67 = 68,
T__68 = 69, T__69 = 70, T__70 = 71, T__71 = 72, T__72 = 73, T__73 = 74,
T__74 = 75, T__75 = 76, T__76 = 77, T__77 = 78, T__78 = 79, T__79 = 80,
T__80 = 81, T__81 = 82, T__82 = 83, T__83 = 84, NEWLINE = 85, WHITESPACE = 86,
INTEGER10 = 87, INTEGER16 = 88, INTEGER8 = 89, INTEGER2 = 90, FLOATVAL = 91,
BUILTIN = 92, BOOL_VALUE = 93, UNDEFINED_VALUE = 94, IDENTIFIER = 95,
STRUCT_IDENTIFIER = 96, PATH = 97, STRING = 98, HASHSTRING = 99
T__80 = 81, T__81 = 82, T__82 = 83, T__83 = 84, T__84 = 85, T__85 = 86,
T__86 = 87, T__87 = 88, NEWLINE = 89, WHITESPACE = 90, INTEGER10 = 91,
INTEGER16 = 92, INTEGER8 = 93, INTEGER2 = 94, FLOATVAL = 95, BUILTIN = 96,
BOOL_VALUE = 97, UNDEFINED_VALUE = 98, IDENTIFIER = 99, STRUCT_IDENTIFIER = 100,
PATH = 101, STRING = 102, HASHSTRING = 103
};

enum {
Expand All @@ -44,9 +45,9 @@ class gscParser : public antlr4::Parser {
RuleExpression6 = 31, RuleExpression7 = 32, RuleExpression8 = 33, RuleExpression9 = 34,
RuleExpression10 = 35, RuleExpression11 = 36, RuleExpression12 = 37,
RuleExpression13 = 38, RuleExpression14 = 39, RuleExpression15 = 40,
RuleFunction_call_exp = 41, RuleFunction_call = 42, RuleLeft_value = 43,
RuleConst_expr = 44, RuleFunction_ref = 45, RuleNumber = 46, RuleVector_value = 47,
RuleArray_def = 48, RuleStruct_def = 49, RuleIdf = 50
RuleIs_expression = 41, RuleFunction_call_exp = 42, RuleFunction_call = 43,
RuleLeft_value = 44, RuleConst_expr = 45, RuleFunction_ref = 46, RuleNumber = 47,
RuleVector_value = 48, RuleArray_def = 49, RuleStruct_def = 50, RuleIdf = 51
};

explicit gscParser(antlr4::TokenStream *input);
Expand Down Expand Up @@ -107,6 +108,7 @@ class gscParser : public antlr4::Parser {
class Expression13Context;
class Expression14Context;
class Expression15Context;
class Is_expressionContext;
class Function_call_expContext;
class Function_callContext;
class Left_valueContext;
Expand Down Expand Up @@ -675,6 +677,7 @@ class gscParser : public antlr4::Parser {
virtual size_t getRuleIndex() const override;
Expression13Context *expression13();
Left_valueContext *left_value();
Is_expressionContext *is_expression();


virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
Expand Down Expand Up @@ -725,6 +728,21 @@ class gscParser : public antlr4::Parser {

Expression15Context* expression15();

class Is_expressionContext : public antlr4::ParserRuleContext {
public:
Is_expressionContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
Expression13Context *expression13();
antlr4::tree::TerminalNode *IDENTIFIER();
antlr4::tree::TerminalNode *UNDEFINED_VALUE();


virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override;

};

Is_expressionContext* is_expression();

class Function_call_expContext : public antlr4::ParserRuleContext {
public:
Function_call_expContext(antlr4::ParserRuleContext *parent, size_t invokingState);
Expand Down
2 changes: 2 additions & 0 deletions src/acts/compiler/gscVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ class gscVisitor : public antlr4::tree::AbstractParseTreeVisitor {

virtual std::any visitExpression15(gscParser::Expression15Context *context) = 0;

virtual std::any visitIs_expression(gscParser::Is_expressionContext *context) = 0;

virtual std::any visitFunction_call_exp(gscParser::Function_call_expContext *context) = 0;

virtual std::any visitFunction_call(gscParser::Function_callContext *context) = 0;
Expand Down
75 changes: 75 additions & 0 deletions src/acts/compiler/gsc_compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3773,6 +3773,81 @@ namespace acts::compiler {
}
}
break;
case gscParser::RuleIs_expression: {
if (!ParseExpressionNode(rule->children[0], parser, obj, fobj, expressVal)) {
return false;
}
bool hasNot = rule->children.size() >= 3 && rule->children[2]->getText() == "not";
// defs:
// a is hash|int|etc. -> use ishash(a) functions
// a is true -> use is_true operator (mw) or super equal (others)
// a is false -> super equal (others) / mw???
// a is undefined -> !isdefined(a)

std::string typeName = rule->children[rule->children.size() - 1]->getText();
uint64_t typeNameHash = hash::Hash64(typeName.data());

if (typeNameHash == hash::Hash64("undefined")) {
if (hasNot) {
fobj.AddNode(rule, new AscmNodeOpCode(OPCODE_IsDefined));
}
else {
fobj.AddNode(rule, new AscmNodeOpCode(OPCODE_IsDefined));
fobj.AddNode(rule, new AscmNodeOpCode(OPCODE_BoolNot));
}
return true;
}

if (typeNameHash == hash::Hash64("defined")) {
fobj.AddNode(rule, new AscmNodeOpCode(OPCODE_IsDefined));
if (hasNot) {
fobj.AddNode(rule, new AscmNodeOpCode(OPCODE_BoolNot));
}
return true;
}

if (typeNameHash == hash::Hash64("true")) {
if (obj.HasOpCode(OPCODE_IW_IsTrue)) {
fobj.AddNode(rule, new AscmNodeOpCode(OPCODE_IW_IsTrue));
if (hasNot) {
fobj.AddNode(rule, new AscmNodeOpCode(OPCODE_BoolNot));
}
return true;
}

fobj.AddNode(rule, obj.BuildAscmNodeData(1));
fobj.AddNode(rule, new AscmNodeOpCode(hasNot ? OPCODE_SuperNotEqual : OPCODE_SuperEqual));
return true;
}

if (typeNameHash == hash::Hash64("false")) {
// todo: find implementation for mwiii

fobj.AddNode(rule, obj.BuildAscmNodeData(0));
fobj.AddNode(rule, new AscmNodeOpCode(hasNot ? OPCODE_SuperNotEqual : OPCODE_SuperEqual));
return true;
}

auto dtit = obj.vmInfo->dataType.find(typeNameHash);

if (dtit == obj.vmInfo->dataType.end()) {
obj.info.PrintLineMessage(alogs::LVL_WARNING, rule, std::format("Can't find datatype '{}' for this VM", typeName));
return false;
}

const char* name = utils::va("is%s", dtit->second);
obj.AddHash(name);
uint64_t funcName = obj.vmInfo->HashField(name);
AscmNodeFunctionCall* asmc = new AscmNodeFunctionCall(OPCODE_CallBuiltinFunction, 0, 1, funcName, obj.currentNamespace, obj.vmInfo);
obj.AddImport(asmc, obj.currentNamespace, funcName, 1, tool::gsc::T8GSCImportFlags::FUNCTION | tool::gsc::T8GSCImportFlags::GET_CALL);
fobj.AddNode(rule, asmc);

// reverse the op if possible
if (hasNot) {
fobj.AddNode(rule, new AscmNodeOpCode(OPCODE_BoolNot));
}
return true;
}
case gscParser::RuleConst_expr:
case gscParser::RuleNumber:
case gscParser::RuleExpression13:
Expand Down
2 changes: 1 addition & 1 deletion src/acts/compiler/preprocessor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ namespace acts::compiler::preprocessor {
else if (line.starts_with("#warning")) {
errorHandler(alogs::LVL_WARNING, lineIdx, std::string{ line.substr(line.length() > 8 ? 9 : 8) });
}
else {
else if (!line.starts_with("#region") && line.starts_with("#endregion")) {
if (eraseCtx.empty() || !eraseCtx.top()) {
lineStart = next + 1;
continue;
Expand Down
26 changes: 26 additions & 0 deletions src/acts/tools/gsc_opcodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4829,6 +4829,32 @@ namespace tool::gsc::opcode {
}

return ref->second.RemapSamePlatform(origin);
}

void RegisterDatatypeRenamed(byte vm, const char* datatype, const char* trueName) {
auto ref = g_opcodeMap.find(vm);
if (ref == g_opcodeMap.end()) {
assert(0);
LOG_ERROR("Registering unknown DevCall vm 0x{:x}", (int)vm);
return;
}

auto& opnfo = ref->second;

opnfo.dataType[hash::Hash64(datatype)] = trueName;
}

void RegisterDatatype(byte vm, const char* datatype) {
auto ref = g_opcodeMap.find(vm);
if (ref == g_opcodeMap.end()) {
assert(0);
LOG_ERROR("Registering unknown DevCall vm 0x{:x}", (int)vm);
return;
}

auto& opnfo = ref->second;

opnfo.dataType[hash::Hash64(datatype)] = datatype;
}

void RegisterDevCall(byte vm, const char* devCall) {
Expand Down
11 changes: 11 additions & 0 deletions src/acts/tools/gsc_opcodes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ namespace tool::gsc::opcode {
std::unordered_map<Platform, std::unordered_map<OPCode, std::vector<uint16_t>>> opcodemappltlookup{};
std::unordered_map<uint64_t, GlobalVariableDef> globalvars{};
std::unordered_map<uint64_t, FunctionOperator> opFuncs{};
std::unordered_map<uint64_t, const char*> dataType{};
std::unordered_map<Platform, Platform> sameVmMap{};

/*
Expand Down Expand Up @@ -135,6 +136,8 @@ namespace tool::gsc::opcode {
Platform RemapSamePlatform(byte vm, Platform origin);
void SetMaxOpCode(byte vm, uint16_t maxOpCode);
void RegisterDevCall(byte vm, const char* devCall);
void RegisterDatatypeRenamed(byte vm, const char* datatype, const char* trueName);
void RegisterDatatype(byte vm, const char* datatype);
void RegisterOpCodes();

inline void RegisterOpCode(byte vm, Platform platform, OPCode enumValue) {}
Expand All @@ -152,4 +155,12 @@ namespace tool::gsc::opcode {
RegisterDevCall(vm, calls...);
}


inline void RegisterDatatype(byte vm) {}
template<typename... Datatypes>
inline void RegisterDatatype(byte vm, const char* datatype, Datatypes... datatypes) {
RegisterDatatype(vm, datatype);
RegisterDatatype(vm, datatypes...);
}

}
14 changes: 14 additions & 0 deletions src/acts/tools/gsc_opcodes_load.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ namespace tool::gsc::opcode {
RegisterVMOperatorFunction(VM_T8, "waittillframeend", "waittillframeend()", OPCODE_WaitTillFrameEnd, VPFD_NONE, 0, 0);
RegisterVMHashOPCode(VM_T8, '#', OPCODE_GetHash, 8, [](const char* str) { return hash::Hash64(str); });
RegisterDevCall(VM_T8, "assert", "assertmsg", "errormsg", "throw", "println");
RegisterDatatype(VM_T8, "functionptr", "scriptfunctionptr", "codefunctionptr", "string", "array", "weapon", "int", "float", "vec", "class", "struct", "hash");
RegisterDatatypeRenamed(VM_T8, "function", "functionptr");


RegisterOpCode(VM_T8, PLATFORM_PC, OPCODE_Abort, 0x0);
Expand Down Expand Up @@ -346,6 +348,8 @@ namespace tool::gsc::opcode {
RegisterVMOperatorFunction(VM_T937, "waittillframeend", "waittillframeend()", OPCODE_WaitTillFrameEnd, VPFD_NONE, 0, 0);
RegisterVMHashOPCode(VM_T937, '#', OPCODE_GetHash, 8, [](const char* str) { return hash::Hash64(str); });
RegisterDevCall(VM_T937, "assert", "assertmsg", "errormsg", "throw", "println");
RegisterDatatype(VM_T937, "functionptr", "scriptfunctionptr", "codefunctionptr", "string", "array", "weapon", "int", "float", "vec", "class", "struct", "hash");
RegisterDatatypeRenamed(VM_T937, "function", "functionptr");

RegisterOpCode(VM_T937, PLATFORM_PLAYSTATION, OPCODE_Nop, 0x13, 0x16, 0x19, 0x1a, 0x21, 0x24, 0x2a, 0x2c, 0x31, 0x33, 0x35, 0x38, 0x39, 0x3c, 0x3e, 0x41, 0x43, 0x4a);
RegisterOpCode(VM_T937, PLATFORM_PLAYSTATION, OPCODE_Nop, 0x4b, 0x4c, 0x4d, 0x57, 0x59, 0x5b, 0x5c, 0x5d, 0x5e, 0x62, 0x63, 0x65, 0x66, 0x68, 0x6d, 0x6e, 0x73, 0x74, 0x75, 0x76, 0x77, 0x7b, 0x83, 0x86, 0x87, 0x8d);
Expand Down Expand Up @@ -650,6 +654,8 @@ namespace tool::gsc::opcode {
RegisterVMOperatorFunction(VM_T9, "waittillframeend", "waittillframeend()", OPCODE_WaitTillFrameEnd, VPFD_NONE, 0, 0);
RegisterVMHashOPCode(VM_T9, '#', OPCODE_GetHash, 8, [](const char* str) { return hash::Hash64(str); });
RegisterDevCall(VM_T9, "assert", "assertmsg", "errormsg", "throw", "println");
RegisterDatatype(VM_T9, "functionptr", "scriptfunctionptr", "codefunctionptr", "string", "array", "weapon", "int", "float", "vec", "class", "struct", "hash");
RegisterDatatypeRenamed(VM_T9, "function", "functionptr");

RegisterOpCode(VM_T9, PLATFORM_PC, OPCODE_Abort, 0x0);
RegisterOpCode(VM_T9, PLATFORM_PC, OPCODE_Nop, 0x1);
Expand Down Expand Up @@ -896,6 +902,7 @@ namespace tool::gsc::opcode {
RegisterVMHashOPCode(VM_MW23, '%', OPCODE_IW_GetUnk9, 8, [](const char* str) { return hash::Hash64(str, 0x47F5817A5EF961BA); });
RegisterVMHashOPCode(VM_MW23, 't', OPCODE_IW_GetUnkb, 4, [](const char* str) { return hash::Hash64(str, 0x811C9DC5, 0x1000193) & 0xFFFFFFFF; });
RegisterDevCall(VM_MW23, "assert", "assertmsg", "assertex", "println");
RegisterDatatype(VM_MW23, "builtinfunction", "builtinmethod", "function", "string", "istring", "struct", "int", "float", "vector", "class", "struct");

RegisterVM(VM_MW23B, "Call of Duty: Modern Warfare III (8B)", "jup8b", "mwiii", VmFlags::VMF_HASH64 | VmFlags::VMF_NO_PARAM_FLAGS | VmFlags::VMF_FULL_FILE_NAMESPACE | VmFlags::VMF_HASH_IW | VmFlags::VMF_CALL_NO_PARAMS | VmFlags::VMF_IW_CALLS);
RegisterVMPlatform(VM_MW23B, PLATFORM_PC);
Expand All @@ -915,6 +922,7 @@ namespace tool::gsc::opcode {
RegisterVMHashOPCode(VM_MW23B, '%', OPCODE_IW_GetUnk9, 8, [](const char* str) { return hash::Hash64(str, 0x47F5817A5EF961BA); });
RegisterVMHashOPCode(VM_MW23B, 't', OPCODE_IW_GetUnkb, 4, [](const char* str) { return hash::Hash64(str, 0x811C9DC5, 0x1000193) & 0xFFFFFFFF; });
RegisterDevCall(VM_MW23B, "assert", "assertmsg", "assertex", "println");
RegisterDatatype(VM_MW23B, "builtinfunction", "builtinmethod", "function", "string", "istring", "struct", "int", "float", "vector", "class", "struct");
#ifdef SP23_INCLUDES
sp23::opcodes::RegisterMW23OpCodes();
#endif
Expand All @@ -936,6 +944,8 @@ namespace tool::gsc::opcode {
RegisterVMOperatorFunction(VM_T7, "waittillframeend", "waittillframeend()", OPCODE_WaitTillFrameEnd, VPFD_NONE, 0, 0);
RegisterVMHashOPCode(VM_T7, '#', OPCODE_GetHash32, 4, [](const char* str) { return hashutils::HashT7(str); });
RegisterDevCall(VM_T7, "assert", "assertmsg", "errormsg", "throw", "println");
RegisterDatatype(VM_T7, "functionptr", "string", "array", "weapon", "int", "float", "vec");
RegisterDatatypeRenamed(VM_T7, "function", "functionptr");
SetMaxOpCode(VM_T7, 0x1FFF);

RegisterOpCode(VM_T7, PLATFORM_PC, OPCODE_Nop, 0x12, 0x14, 0x16, 0x17, 0x1a, 0x1d, 0x1f, 0x21, 0x29, 0x2f, 0x32, 0x34, 0x37, 0x38, 0x3b, 0x3d, 0x40, 0x48, 0x51, 0x52, 0x55, 0x56, 0x58, 0x5c, 0x5e, 0x65, 0x6d, 0x6e, 0x6f, 0x71, 0x73, 0x74, 0x7b, 0x7c, 0x7f, 0x80, 0x81, 0x85, 0x87, 0x88, 0x8d, 0x8e, 0x91, 0x92, 0x93, 0x94, 0x97, 0x99, 0x9a, 0xa4, 0xa5, 0xac, 0xb5, 0xb8, 0xb9, 0xba, 0xbd, 0xc3, 0xc5, 0xcb, 0xcd, 0xcf, 0xd1, 0xd3, 0xd6, 0xde, 0xe1, 0xe2, 0xe6, 0xe7, 0xe8, 0xee, 0xf3, 0xf8, 0xf9, 0xfa, 0xfd, 0x101, 0x10a, 0x10f, 0x113, 0x114, 0x119, 0x11e, 0x11f, 0x120, 0x121, 0x127, 0x129, 0x12a, 0x12d, 0x130, 0x134, 0x135, 0x138, 0x139, 0x13c, 0x142, 0x148, 0x14d, 0x151, 0x154);
Expand Down Expand Up @@ -1118,6 +1128,8 @@ namespace tool::gsc::opcode {
RegisterVMOperatorFunction(VM_T71B, "waittillframeend", "waittillframeend()", OPCODE_WaitTillFrameEnd, VPFD_NONE, 0, 0);
RegisterVMHashOPCode(VM_T71B, '#', OPCODE_GetHash32, 4, [](const char* str) { return hashutils::HashT7(str); });
RegisterDevCall(VM_T71B, "assert", "assertmsg", "errormsg", "throw", "println");
RegisterDatatype(VM_T71B, "functionptr", "string", "array", "weapon", "int", "float", "vec");
RegisterDatatypeRenamed(VM_T71B, "function", "functionptr");
SetMaxOpCode(VM_T71B, 0xFF);


Expand Down Expand Up @@ -1231,6 +1243,8 @@ namespace tool::gsc::opcode {
RegisterVMPlatform(VM_T831, PLATFORM_PLAYSTATION);
SetMaxOpCode(VM_T831, 0xFFF);
RegisterDevCall(VM_T831, "assert", "assertmsg", "errormsg", "throw", "println");
RegisterDatatype(VM_T831, "functionptr", "string", "array", "weapon", "int", "float", "vec");
RegisterDatatypeRenamed(VM_T831, "function", "functionptr");

RegisterOpCode(VM_T831, PLATFORM_PLAYSTATION, OPCODE_Abort, 0x0);
RegisterOpCode(VM_T831, PLATFORM_PLAYSTATION, OPCODE_Nop, 0x1);
Expand Down
25 changes: 24 additions & 1 deletion test/gsc-compiler/acts_t7.gsc
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,30 @@ function __pre_init__() {

};
test2 = function(a, b, c) {

if (a is true) {
self iprintln("true");
}
if (a is functionptr) {
self iprintln("function");
}
if (a is defined) {
self iprintln("defined");
}
if (a is not defined) {
self iprintln("undefined");
}
if (a is undefined) {
self iprintln("undefined");
}
if (a is not undefined) {
self iprintln("defined");
}
if (a is false) {
self iprintln("false");
}
if (a is int) {
self iprintln("int");
}
};
}

Expand Down

0 comments on commit a110cb9

Please sign in to comment.