diff --git a/source/language.d b/source/language.d index d0bfe0e..7e96573 100644 --- a/source/language.d +++ b/source/language.d @@ -31,14 +31,16 @@ final class AssignStatement : Statement Type type; VarExpression dest; Expression expr; + bool isConst; - this (int lineId_, Type type_, VarExpression dest_, Expression expr_) + this (int lineId_, Type type_, VarExpression dest_, Expression expr_, bool isConst_ = false) { lineId = lineId_; type = type_; dest = dest_; expr = expr_; complexity = 1 + dest.complexity + expr.complexity; + isConst = isConst_; } } diff --git a/source/parser.d b/source/parser.d index f1b8fb4..bca0785 100644 --- a/source/parser.d +++ b/source/parser.d @@ -499,9 +499,21 @@ final class StatementParser "indent does not match"); t.popFront (); + + bool isConst = false; + if (!line.tokens.empty && line.tokens.front == "const") + { + isConst = true; + line.tokens.popFront(); + } + auto var = cast (VarExpression) (parseExpression (line)); check (var !is null, line, - "assign statement detected but left side not parsed"); + "assign statement detected but left side not parsed"); + if (isConst && var.index !is null) + { + throw new Exception("cannot declare array element as constant"); + } check (!line.tokens.empty, line, "expected assignment operator, found end of line"); @@ -528,7 +540,7 @@ final class StatementParser check (line.tokens.empty, line, "extra token at end of line: " ~ line.tokens.front); - return new AssignStatement (line.lineId, type, var, cur); + return new AssignStatement (line.lineId, type, var, cur, isConst); } Statement parseStatement (string prevIndent) diff --git a/source/runner.d b/source/runner.d index 19713d0..5cffedb 100644 --- a/source/runner.d +++ b/source/runner.d @@ -110,7 +110,7 @@ class Runner } } - long * varAddress (string name, bool canCreate = false) + long * varAddress (string name, bool canCreate = false, bool isConst = false) { foreach_reverse (ref cur; state) { @@ -119,7 +119,7 @@ class Runner if (cur.vars[name].isConst) { throw new Exception ("variable " ~ name ~ - " is constant"); + " is constant"); } return &(cur.vars[name].value); } @@ -128,11 +128,11 @@ class Runner { throw new Exception ("no such variable: " ~ name); } - state.back.vars[name] = Var (0); + state.back.vars[name] = Var (0, isConst); return &(state.back.vars[name].value); } - long * arrayAddress (string name, long index) + long * arrayAddress (string name, long index, bool isConst = false) { foreach_reverse (ref cur; state) { @@ -141,7 +141,7 @@ class Runner if (cur.arrays[name].isConst) { throw new Exception ("array " ~ name ~ - " is constant"); + " is constant"); } if (index < 0 || cur.arrays[name].contents.length <= index) @@ -306,17 +306,17 @@ class Runner assert (false); } - long * getAddr (VarExpression dest, bool canCreate) + long * getAddr (VarExpression dest, bool canCreate, bool isConst = false) { long * res; if (dest.index is null) { - res = varAddress (dest.name, canCreate); + res = varAddress (dest.name, canCreate, isConst); } else { auto indexValue = evalExpression (dest.index); - res = arrayAddress (dest.name, indexValue); + res = arrayAddress (dest.name, indexValue, isConst); } return res; } @@ -372,7 +372,7 @@ class Runner return; } - auto addr = getAddr (cur.dest, true); + auto addr = getAddr (cur.dest, true, cur.isConst); auto value = control.queues[otherId][id].pop (); doAssign (cur, addr, value); @@ -409,11 +409,17 @@ class Runner { if (cur.dest.name in curState.arrays) { + if(cur.isConst) + throw new Exception + ("array: array cannot be constant"); curState.arrays[cur.dest.name] = Array (new long [values[0].to !(size_t)]); return; } } + if(cur.isConst) + throw new Exception + ("array: array cannot be constant"); state.back.arrays[cur.dest.name] = Array (new long [values[0].to !(size_t)]); } @@ -438,8 +444,37 @@ class Runner return; } + if(isConst && type == Type.assign) + { + auto varExpr = cast(VarExpression)(expr); + if (varExpr !is null && varExpr.name == dest.name && varExpr.index is null) + { + throw new Exception + ("cannot initialize constant " ~ dest.name ~ " with itself"); + } + } + auto value = evalExpression (expr); - auto addr = getAddr (dest, type == Type.assign); + auto addr = getAddr (dest, type == Type.assign, isConst); + + + + if(isConst && type == Type.assign) + { + auto varExpr = cast(VarExpression)(expr); + foreach_reverse(ref curState; state) + { + + if(dest.name in curState.vars) + { + if(dest.name in curState.vars && !curState.vars[dest.name].isConst) + throw new Exception + ("redefinition of variable " ~ dest.name ~ " as constant"); + curState.vars[dest.name].isConst = true; + break; + } + } + } doAssign (cur0, addr, value); delay = complexity; return; diff --git a/syntax.txt b/syntax.txt index 86e6414..1d2e90e 100644 --- a/syntax.txt +++ b/syntax.txt @@ -21,6 +21,7 @@ function ( ) : \n is +const is @@ -120,4 +121,4 @@ if : \n \n is elif : \n elif : \n \n else \n -elif : \n \n +elif : \n \n \ No newline at end of file