// the expected return type of the operation override public ValueType Type(MiniPL.Runnable context) { switch (op) { case '+': ValueType t = lhs.Type(context); if (t == ValueType.String) { return(t); } return(ValueType.Integer); case '-': return(ValueType.Integer); case '*': return(ValueType.Integer); case '/': return(ValueType.Integer); case '<': return(ValueType.Boolean); case '=': return(ValueType.Boolean); case '&': return(ValueType.Boolean); default: throw new Exception("UNEXPECTER OPERATOR " + op); } }
public override void TypeCheck(MiniPL.Runnable context) { // typecheck value expr.TypeCheck(context); // check that value type matches variable switch (context.declarations[identifier].Type) { case ValueType.Boolean: if (expr.Type(context) == ValueType.String) { context.errors.Add(new SemanticError(Token, "cannot assign string value to boolean " + identifier)); } break; case ValueType.Integer: if (expr.Type(context) != ValueType.Integer) { context.errors.Add(new SemanticError(Token, "expected integer type value for " + identifier)); } break; case ValueType.String: if (expr.Type(context) != ValueType.String) { context.errors.Add(new SemanticError(Token, "expected string type value for " + identifier)); } break; } }
// Mini-PL spec only defines reading integer and string values public override void TypeCheck(MiniPL.Runnable context) { if (context.declarations[identifier].Type == ValueType.Boolean) { context.errors.Add(new SemanticError(Token, "cannot read a boolean value")); } }
public override void TypeCheck(MiniPL.Runnable context) { // if initial value specified check it agaist the type if (initialValue != null) { initialValue.TypeCheck(context); switch (type) { case ValueType.Boolean: if (initialValue.Type(context) == ValueType.String) { context.errors.Add(new SemanticError(Token, "cannot assign string value to boolean " + identifier)); } break; case ValueType.Integer: if (initialValue.Type(context) != ValueType.Integer) { context.errors.Add(new SemanticError(Token, "expected integer type value for " + identifier)); } break; case ValueType.String: if (initialValue.Type(context) != ValueType.String) { context.errors.Add(new SemanticError(Token, "expected string type value for " + identifier)); } break; } } }
// recursively check operands and check that their types are compatible with operation override public void TypeCheck(MiniPL.Runnable context) { rhs.TypeCheck(context); lhs.TypeCheck(context); switch (op) { case '+': if (!((rhs.Type(context) == ValueType.Integer && lhs.Type(context) == ValueType.Integer) || (rhs.Type(context) == ValueType.String && lhs.Type(context) == ValueType.String))) { context.errors.Add(new SemanticError(Token, "bad operand types for '+' operation")); } break; case '-': if (!(rhs.Type(context) == ValueType.Integer && lhs.Type(context) == ValueType.Integer)) { context.errors.Add(new SemanticError(Token, "bad operand types for '-' operation")); } break; case '*': if (!(rhs.Type(context) == ValueType.Integer && lhs.Type(context) == ValueType.Integer)) { context.errors.Add(new SemanticError(Token, "bad operand types for '*' operation")); } break; case '/': if (!(rhs.Type(context) == ValueType.Integer && lhs.Type(context) == ValueType.Integer)) { context.errors.Add(new SemanticError(Token, "bad operand types for '/' operation")); } break; case '<': if (!(rhs.Type(context) == ValueType.Integer && lhs.Type(context) == ValueType.Integer)) { context.errors.Add(new SemanticError(Token, "bad operand types for '<' operation")); } break; case '=': if (!(rhs.Type(context) == lhs.Type(context))) { context.errors.Add(new SemanticError(Token, "bad operand types for '=' operation")); } break; case '&': if (rhs.Type(context) == ValueType.String || lhs.Type(context) == ValueType.String) { context.errors.Add(new SemanticError(Token, "bad operand types for '&' operation")); } break; } }
override public void TypeCheck(MiniPL.Runnable context) { expr.TypeCheck(context); if (expr.Type(context) != ValueType.Boolean && expr.Type(context) != ValueType.Integer) { context.errors.Add(new SemanticError(Token, "bad type for '!' operation")); } }
public override void TypeCheck(MiniPL.Runnable context) { // typecheck parameter expr.TypeCheck(context); // Mini-PL spec only defines print for integer and boolean values if (expr.Type(context) == ValueType.Boolean) { context.errors.Add(new SemanticError(Token, "cannot print a boolean value")); } }
public override void TypeCheck(MiniPL.Runnable context) { // typecheck parameter expr.TypeCheck(context); // only defined for boolean parameter, but we'll allow integers too.. if (expr.Type(context) == ValueType.String) { context.errors.Add(new SemanticError(Token, "cannot assert a string value")); } }
public override RuntimeError Execute(MiniPL.Runnable context, TextReader stdin, TextWriter stdout) { if (expr.Type(context) == ValueType.String) { throw new Exception("TYPE CHECKING FAILED"); } // if expression evaluates to false, stop execution with a runtime error if (expr.Evaluate(context).BooleanValue() == false) { return(new RuntimeError(Token, "assertion failed")); } return(null); }
override public Value Evaluate(MiniPL.Runnable context) { if (op == '!') { if (expr.Type(context) == ValueType.Boolean) { return(new Value(!expr.Evaluate(context).BooleanValue())); } if (expr.Type(context) == ValueType.Integer) { return(new Value(expr.Evaluate(context).IntValue() == 0)); } throw new Exception("TYPE CHECKING FAILED"); } throw new Exception("UNEXPECTED OPERATION " + op); }
public override RuntimeError Execute(MiniPL.Runnable context, TextReader stdin, TextWriter stdout) { // print value of parameter to output stream switch (expr.Type(context)) { case ValueType.Integer: stdout.Write(expr.Evaluate(context).IntValue()); break; case ValueType.String: stdout.Write(expr.Evaluate(context).StringValue()); break; default: throw new Exception("TYPE CHECK FAILED"); } return(null); }
// Execute read statement public override RuntimeError Execute(MiniPL.Runnable context, TextReader stdin, TextWriter stdout) { // read whitespace-delimited token from input stream string input = ""; char[] buf = new char[1]; // works well enough for console input but surely there's a better way.. while (true) { int read = stdin.Read(buf, 0, 1); if (read == 0) { break; } if (buf[0] == ' ' || buf[0] == '\t' || buf[0] == '\n') { break; } input += buf[0]; } if (context.declarations[identifier].Type == ValueType.Integer) { // if expecting integer but parsing fails, create runtime error int inputInt = 0; if (!Int32.TryParse(input, out inputInt)) { return(new RuntimeError(Token, "expected to read integer")); } context.values[identifier] = new Value(inputInt); } else if (context.declarations[identifier].Type == ValueType.String) { context.values[identifier] = new Value(input); } else { throw new Exception("TYPE CHECKING FAILED"); } return(null); }
public override RuntimeError Execute(MiniPL.Runnable context, TextReader stdin, TextWriter stdout) { // execute all statements in block for every value of control variable from // value of start expression to value of end expression (inclusive) int start = startVal.Evaluate(context).IntValue(); int end = endVal.Evaluate(context).IntValue(); for (int i = start; i <= end; i++) { context.values[identifier] = new Value(i); foreach (Statement stmt in block) { stmt.Execute(context, stdin, stdout); } } // sample code seemed to indicate control value should be end + 1 after execution context.values[identifier] = new Value(end + 1); return(null); }
public override void TypeCheck(MiniPL.Runnable context) { // typecheck parameters, control variable, and every statement in loop startVal.TypeCheck(context); endVal.TypeCheck(context); if (context.declarations[identifier].Type != ValueType.Integer) { context.errors.Add(new SemanticError(Token, "bad for-loop control type")); } if (startVal.Type(context) != ValueType.Integer) { context.errors.Add(new SemanticError(startVal.Token, "bad for-loop start value type")); } if (endVal.Type(context) != ValueType.Integer) { context.errors.Add(new SemanticError(startVal.Token, "bad for-loop end value type")); } foreach (Statement stmt in block) { stmt.TypeCheck(context); } }
override public ValueType Type(MiniPL.Runnable context) { return(value.Type()); }
override public ValueType Type(MiniPL.Runnable context) { return(ValueType.Boolean); }
public abstract ValueType Type(MiniPL.Runnable context);
public abstract Value Evaluate(MiniPL.Runnable context);
public override RuntimeError Execute(MiniPL.Runnable context, TextReader stdin, TextWriter stdout) { // just update symbol table context.values[identifier] = expr.Evaluate(context); return(null); }
override public void TypeCheck(MiniPL.Runnable context) { // nothing to check }
override public ValueType Type(MiniPL.Runnable context) { return(context.declarations[identifier].Type); }
public abstract void TypeCheck(MiniPL.Runnable context);
public override RuntimeError Execute(MiniPL.Runnable context, TextReader stdin, TextWriter stdout) { // update symbol table to default or specified initial value context.values[identifier] = (initialValue == null) ? new Value(type) : initialValue.Evaluate(context); return(null); }
// apply the appropriate operation on operands override public Value Evaluate(MiniPL.Runnable context) { switch (op) { case '+': if (rhs.Type(context) == ValueType.Integer && lhs.Type(context) == ValueType.Integer) { return(new Value(lhs.Evaluate(context).IntValue() + rhs.Evaluate(context).IntValue())); } if (rhs.Type(context) == ValueType.String && lhs.Type(context) == ValueType.String) { return(new Value(lhs.Evaluate(context).StringValue() + rhs.Evaluate(context).StringValue())); } throw new Exception("TYPECHECKING FAILED"); case '-': if (rhs.Type(context) != ValueType.Integer || lhs.Type(context) != ValueType.Integer) { throw new Exception("TYPECHECKING FAILED"); } return(new Value(lhs.Evaluate(context).IntValue() - rhs.Evaluate(context).IntValue())); case '*': if (rhs.Type(context) != ValueType.Integer || lhs.Type(context) != ValueType.Integer) { throw new Exception("TYPECHECKING FAILED"); } return(new Value(lhs.Evaluate(context).IntValue() * rhs.Evaluate(context).IntValue())); case '/': if (rhs.Type(context) != ValueType.Integer || lhs.Type(context) != ValueType.Integer) { throw new Exception("TYPECHECKING FAILED"); } int denominator = rhs.Evaluate(context).IntValue(); if (denominator == 0) { throw new MiniPL_DivideByZeroException(new RuntimeError(Token, "divide by zero")); } return(new Value(lhs.Evaluate(context).IntValue() / denominator)); case '<': if (rhs.Type(context) != ValueType.Integer || lhs.Type(context) != ValueType.Integer) { throw new Exception("TYPECHECKING FAILED"); } return(new Value(lhs.Evaluate(context).IntValue() < rhs.Evaluate(context).IntValue())); case '=': if (rhs.Type(context) != lhs.Type(context)) { throw new Exception("TYPECHECKING FAILED"); } switch (rhs.Type(context)) { case ValueType.Boolean: return(new Value(rhs.Evaluate(context).BooleanValue() == lhs.Evaluate(context).BooleanValue())); case ValueType.Integer: return(new Value(rhs.Evaluate(context).IntValue() == lhs.Evaluate(context).IntValue())); case ValueType.String: return(new Value(rhs.Evaluate(context).StringValue() == lhs.Evaluate(context).StringValue())); } break; case '&': if (rhs.Type(context) == ValueType.String || lhs.Type(context) == ValueType.String) { throw new Exception("TYPECHECKING FAILED"); } return(new Value(rhs.Evaluate(context).BooleanValue() && lhs.Evaluate(context).BooleanValue())); } throw new Exception("UNEXPECTED OPERATOR " + op); }
override public Value Evaluate(MiniPL.Runnable context) { return(context.values[identifier]); }
override public Value Evaluate(MiniPL.Runnable context) { return(value); }
public abstract RuntimeError Execute(MiniPL.Runnable context, TextReader stdin, TextWriter stdout);