public ParserType Visit(ParserApp app) { var lambdaType = app.Lambda.Accept(this); var expr = app.Expression.Accept(this); if (!(lambdaType is ParserLambdaType)) { throw new ArgumentException("In an application left expression must be a lambda. Type: " + lambdaType.ToString()); } ParserLambdaType lambda = lambdaType as ParserLambdaType; if (!lambda.InputType.Equivalent(expr)) { throw new ArgumentException(String.Format( "In an application the type of the right expression must match the type of the bound variable " + "Expr type: {0} Variable type: {1}", expr.ToString(), lambda.InputType.ToString())); } ParserType logicType = new ParserLogicType(); app.Type = logicType; return(logicType); }
public ParserType Visit(ParserBinder binder) { // idea: copy our current context, add the new bound variable, visit, remove bound variable // then merge back into our current context var newCtx = CloneContext(); newCtx[binder.VariableName] = binder.VariableType; var visitor = new TypeVisitor(newCtx); ParserType subExpr = binder.Expr.Accept(visitor); newCtx.Remove(binder.VariableName); JoinContext(newCtx); if (subExpr.Typ != ParserTypeEnum.Logic || !(subExpr is ParserLogicType)) { throw new ArgumentException("Bound subexpression must be a logical expression. Type: " + subExpr.ToString()); } var logicalExpr = subExpr as ParserLogicType; switch (binder.OpType) { case ParserBinderType.Exists: if ((binder.VariableType.Flags & ParserTypeFlags.Overt) == 0) { throw new ArgumentException("Exists can only bind overt variables"); } ParserType logicType = new ParserLogicType(); binder.Type = logicType; return(logicType); case ParserBinderType.Lambda: ParserType newType = new ParserLambdaType(binder.VariableType); binder.Type = newType; return(newType); case ParserBinderType.The: if (binder.VariableType is ParserNumType) { ParserType numType = new ParserNumType(); binder.Type = numType; return(numType); } else { throw new ArgumentException("'The' binder can only bind Nat types"); } default: throw new ArgumentException("Unknown Binder"); } }