]> git.mxchange.org Git - simgear.git/blobdiff - simgear/nasal/codegen.c
Nasal: support for standard bitwise operators.
[simgear.git] / simgear / nasal / codegen.c
index d1c05ef6254808bc7abf6c20b9e4d5f7f6d44afd..495456a6cf91b72a8901b52742027983dfe96e61 100644 (file)
@@ -7,6 +7,7 @@
 // These are more sensical predicate names in most contexts in this file
 #define LEFT(tok)   ((tok)->children)
 #define RIGHT(tok)  ((tok)->lastChild)
+#define UNARY(tok)  (LEFT(tok) && LEFT(tok) == RIGHT(tok))
 #define BINARY(tok) (LEFT(tok) && RIGHT(tok) && LEFT(tok)->next == RIGHT(tok))
 
 // Forward references for recursion
@@ -147,7 +148,15 @@ static void genEqOp(int op, struct Parser* p, struct Token* t)
 
 static int defArg(struct Parser* p, struct Token* t)
 {
-    if(t->type == TOK_LPAR) return defArg(p, RIGHT(t));
+    if(t->type == TOK_LPAR) {
+        // http://code.google.com/p/flightgear-bugs/issues/detail?id=737
+        // TOK_LPAR can mean multi-value assignment or function call,
+        // disambigaute by checking the rule of the token
+        if (t->rule == PREC_SUFFIX)
+            naParseError(p, "default arguments cannot be function calls", t->line);
+        return defArg(p, RIGHT(t));
+    }
+    
     if(t->type == TOK_MINUS && RIGHT(t) && 
        RIGHT(t)->type == TOK_LITERAL && !RIGHT(t)->str)
     {
@@ -157,6 +166,15 @@ static int defArg(struct Parser* p, struct Token* t)
         RIGHT(t)->num *= -1;
         return defArg(p, RIGHT(t));
     }
+    if(t->type == TOK_CAT && RIGHT(t) &&
+       RIGHT(t)->type == TOK_LITERAL && !RIGHT(t)->str)
+    {
+        /* default arguments are constants, but "~1" parses as two
+         * tokens, so we have to subset the expression generator for that
+         * case */
+        RIGHT(t)->num = ~(int)RIGHT(t)->num;
+        return defArg(p, RIGHT(t));
+    }
     return findConstantIndex(p, t);
 }
 
@@ -477,6 +495,11 @@ static int tokMatch(struct Token* a, struct Token* b)
 static void genBreakContinue(struct Parser* p, struct Token* t)
 {
     int levels = 1, loop = -1, bp, cp, i;
+    // http://code.google.com/p/flightgear-bugs/issues/detail?id=587
+    // Make sure we are inside of a loop
+    if(p->cg->loopTop <= 0)
+        naParseError(p, "break/continue outside of a valid loop", t->line);
+    
     if(RIGHT(t)) {
         if(RIGHT(t)->type != TOK_SYMBOL)
             naParseError(p, "bad break/continue label", t->line);
@@ -536,10 +559,16 @@ static void genAssign(struct Parser* p, struct Token* t)
 {
     struct Token *lv = LEFT(t), *rv = RIGHT(t);
     int len, dummy, var=0;
+    if (!lv)
+        naParseError(p, "bad assignment, missing variable", t->line);
+    else
     if(parListLen(lv) || (lv->type == TOK_VAR && parListLen(RIGHT(lv)))) {
         if(lv->type == TOK_VAR) { lv = RIGHT(lv); var = 1; }
         len = parListLen(lv);
-        if(rv->type == TOK_LPAR) {
+        // http://code.google.com/p/flightgear-bugs/issues/detail?id=585
+        // TOK_LPAR can mean multi-value assignment or function call,
+        // disambigaute by checking the rule of the token
+        if(rv->type == TOK_LPAR && rv->rule != PREC_SUFFIX) {
             if(len != parListLen(rv))
                 naParseError(p, "bad assignment count", rv->line);
             genCommaList(p, LEFT(rv));
@@ -615,12 +644,16 @@ static void genExpr(struct Parser* p, struct Token* t)
         else genExpr(p, LEFT(t));
         break;
     case TOK_LBRA:
-        if(BINARY(t)) {
-            genExtract(p, t);
-        } else {
+        if(UNARY(t)) {
             emit(p, OP_NEWVEC);
             genList(p, LEFT(t), 1);
         }
+        else if(BINARY(t)) {
+            genExtract(p, t);
+        } else {
+            // forbid usage as 'vec[]'
+            naParseError(p, "missing index or slice expression(s)", t->line);
+        }
         break;
     case TOK_LCURL:
         emit(p, OP_NEWHASH);
@@ -654,6 +687,21 @@ static void genExpr(struct Parser* p, struct Token* t)
         genExpr(p, RIGHT(t)); // unary negation (see also TOK_MINUS!)
         emit(p, OP_NEG);
         break;
+    case TOK_CAT:
+        if(BINARY(t)) {
+            genBinOp(OP_CAT,    p, t); // string concatenation
+        } else if(RIGHT(t) && RIGHT(t)->type == TOK_LITERAL && !RIGHT(t)->str) {
+            RIGHT(t)->num = ~(int)RIGHT(t)->num; // Pre-negate constants
+            genScalarConstant(p, RIGHT(t));
+        } else {
+            genExpr(p, RIGHT(t));       // unary, bitwise negation
+            emit(p, OP_BIT_NEG);
+        }
+        break;
+    case TOK_BIT_NEG:
+        genExpr(p, RIGHT(t)); // unary, bitwise negation (see also TOK_CAT!)
+        emit(p, OP_BIT_NEG);
+        break;
     case TOK_DOT:
         genExpr(p, LEFT(t));
         if(!RIGHT(t) || RIGHT(t)->type != TOK_SYMBOL)
@@ -666,10 +714,12 @@ static void genExpr(struct Parser* p, struct Token* t)
     case TOK_AND: case TOK_OR:
         genShortCircuit(p, t);
         break;
+    case TOK_BIT_AND:genBinOp(OP_BIT_AND, p, t); break;
+    case TOK_BIT_OR: genBinOp(OP_BIT_OR,  p, t); break;
+    case TOK_BIT_XOR:genBinOp(OP_BIT_XOR, p, t); break;
     case TOK_MUL:   genBinOp(OP_MUL,    p, t); break;
     case TOK_PLUS:  genBinOp(OP_PLUS,   p, t); break;
     case TOK_DIV:   genBinOp(OP_DIV,    p, t); break;
-    case TOK_CAT:   genBinOp(OP_CAT,    p, t); break;
     case TOK_LT:    genBinOp(OP_LT,     p, t); break;
     case TOK_LTE:   genBinOp(OP_LTE,    p, t); break;
     case TOK_EQ:    genBinOp(OP_EQ,     p, t); break;
@@ -681,6 +731,9 @@ static void genExpr(struct Parser* p, struct Token* t)
     case TOK_MULEQ:   genEqOp(OP_MUL, p, t);   break;
     case TOK_DIVEQ:   genEqOp(OP_DIV, p, t);   break;
     case TOK_CATEQ:   genEqOp(OP_CAT, p, t);   break;
+    case TOK_BIT_ANDEQ: genEqOp(OP_BIT_AND, p, t); break;
+    case TOK_BIT_OREQ:  genEqOp(OP_BIT_OR,  p, t); break;
+    case TOK_BIT_XOREQ: genEqOp(OP_BIT_XOR, p, t); break;
     default:
         naParseError(p, "parse error", t->line);
     };