private static Expression ParseSExpression(SExpression sExpression) { var expressions = sExpression.Tokens.Select(ct => ParseExpression(ct)).ToArray(); if (expressions.Any() && expressions.First() is SpecialFormToken) { return(ParseSpecialForm((expressions.First() as SpecialFormToken).Token, expressions.Skip(1).ToList(), sExpression)); } return(new Application(expressions)); }
private static Expression ParseSpecialForm(string specialForm, List <Expression> expressions, SExpression sExpression) { if (specialForm == "if") { if (expressions.Count < 2) { throw new ParseException(sExpression.ToString(), "An \"if\" expression must contains at least 2 arguments"); } if (expressions.Count > 3) { throw new ParseException(sExpression.ToString(), "An \"if\" expression must contains at most 3 arguments"); } var falseBranch = expressions.Count == 3 ? expressions[2] : new PrimitiveWrapper <bool>() { Value = false }; return(new If(expressions[0], expressions[1], falseBranch)); } if (specialForm == "define") { if (expressions[0] is Variable) { if (expressions.Count != 2) { throw new ParseException(sExpression.ToString(), "A variable type \"define\" expression must contains exactly 2 arguments"); } return(new Define(expressions[0], expressions[1])); } if (expressions[0] is Application) { if (expressions.Count == 1) { throw new ParseException(sExpression.ToString(), "A procedure type \"define\" expression must contains at least 2 arguments"); } var name = expressions[0]; var defined = MakeBeginIfNeeded(expressions.Skip(1).ToList()); return(new Define(name, defined)); } throw new ParseException(sExpression.ToString(), "A \"define\" expression's first part must be either a string or a list"); } if (specialForm == "lambda") { if (expressions.Count == 1) { throw new ParseException(sExpression.ToString(), "A \"lambda\" expression must contains at least 2 arguments"); } var defined = MakeBeginIfNeeded(expressions.Skip(1).ToList()); if (!(expressions[0] is Application)) { throw new ParseException(sExpression.ToString(), "A \"lambda\" expression's first part must be a list"); } var formalArgs = (expressions[0] as Application).Expressions; if (formalArgs.Any(e => !(e is Variable))) { throw new ParseException(sExpression.ToString(), "A \"lambda\" expression's first part must be a list of arguments"); } return(new Lambda((expressions[0] as Application).Expressions.Cast <Variable>().ToArray(), defined)); } if (specialForm == "let" || specialForm == "let*") { if (expressions.Count < 2) { throw new ParseException(sExpression.ToString(), string.Format("A \"{0}\" expression must contains at least 2 arguments", specialForm)); } if (!(expressions[0] is Application)) { throw new ParseException(sExpression.ToString(), string.Format("A \"{0}\" expression's first part must be a list", specialForm)); } var tuples = new List <Tuple <Variable, Expression> >(); foreach (var expression in (expressions[0] as Application).Expressions) { if (!(expression is Application && (expression as Application).Expressions.Length == 2)) { throw new ParseException(sExpression.ToString(), string.Format("A \"{0}\" definition must be a two-element list", specialForm)); } var applcation = expression as Application; if (!(applcation.Expressions[0] is Variable)) { throw new ParseException(sExpression.ToString(), string.Format("A \"{0}\" definition must begin with a variable", specialForm)); } tuples.Add(new Tuple <Variable, Expression>(applcation.Expressions[0] as Variable, applcation.Expressions[1])); } var body = MakeBeginIfNeeded(expressions.Skip(1).ToList()); if (specialForm == "let") { return(new Let(tuples, body)); } else if (specialForm == "let*") { return(new LetStar(tuples, body)); } } if (specialForm == "begin") { return(new Begin(expressions)); } if (specialForm == "cond") { var last = expressions.Last() as Application; Expression condition = last.Expressions[0]; if (last.Expressions[0] is SpecialToken && (last.Expressions[0] as SpecialToken).Token == "else") { condition = new PrimitiveWrapper <bool>() { Value = true } } ; var accIf = new If(condition, last.Expressions[1], Void.Instance); return(expressions.Cast <Application>().Reverse().Skip(1) .Aggregate(accIf, (acc, x) => new If(x.Expressions[0], x.Expressions[1], acc))); } if (specialForm == "delay") { var expr = expressions.Single(); return(new Promise(expr)); } throw new InternalException(string.Format("Illegal special form {0}", specialForm)); }