// (let () ...) public static AST Expand(Syntax stx, Environment env) { var list = stx.AsLinkedList <Value>(); var argc = GetArgsCount(list); AssertArgsMinimum("let", "arity mismatch", 2, argc, list, stx); var keyword = list[0].AsSyntax(); // let arguments var arguments = list[1].AsSyntax(); // let arguments if (!arguments.IsExpression) { throw SchemeError.SyntaxError("let", "bad syntax (missing name or binding pairs)", stx); } var localEnv = ArgumentsParser.ParseLet(stx, arguments.AsLinkedList <Value>(), env); AST lambda = new AstLambda(stx, keyword, localEnv, AstBuilder.ExpandListElements(list, 2, localEnv)); var result = new LinkedList <Value>(); result.AddLast(lambda.ToValue()); foreach (var v in localEnv) { if (v is ArgumentBinding) { var arg = v as ArgumentBinding; if (arg.ArgType == ArgumentBinding.Type.Required) { result.AddLast(new Value(arg.Initializer)); } } } return(new AstApplication(stx, result)); }
private static Syntax ParseVector(Token thisToken, Tokenizer moreTokens) { var listContents = new List <object>(); Token dotToken = null; var nextToken = moreTokens.ReadToken(); while (nextToken != null && nextToken.Type != TokenType.CloseBracket) { // Parse this token listContents.Add(ParseToken(nextToken, moreTokens)); // Fetch the next token nextToken = moreTokens.ReadToken(); if (nextToken == null) { throw SchemeError.SyntaxError("parser", "Improperly formed list.", dotToken); } //if (!improper && nextToken.Type == TokenType.Symbol && dotSymbol.Equals(nextToken.Value) && thisToken.Type == TokenType.OpenBracket) if (nextToken.Type == TokenType.Dot) { throw SchemeError.SyntaxError("parser", "Improperly formed dotted list", nextToken); } } if (nextToken == null) // Missing ')' { throw SchemeError.SyntaxError("parser", "Missing close parenthesis", thisToken); } return(new Syntax(ValueList.FromList(listContents), thisToken)); }
// retrieve a quoted sugar token (' ` , ,@) and advance our position private Token QuoteSugar() { TokenType type; builder.Clear(); switch (Character) { case '\'': type = TokenType.Quote; break; case '`': type = TokenType.QuasiQuote; break; case ',': type = TokenType.Unquote; break; default: throw SchemeError.SyntaxError("tokenizer", "unexpected character", lastToken); } builder.Append((char)Character); NextChar(); if (Character == '@') { type = TokenType.UnquoteSplicing; NextChar(); builder.Append((char)Character); } return(DefineToken(type, builder.ToString())); }
/// <summary> /// Turns thisToken into an object, using moreTokens to get further tokens if required /// </summary> /// <returns></returns> protected static Syntax ParseToken(Token thisToken, Tokenizer moreTokens) { if (thisToken == null) { throw SchemeError.SyntaxError("parser", "unexpectedly reached the end of the input", moreTokens.LastToken); } switch (thisToken.Type) { //case TokenType.Dot: // return thisToken; //TODO maybe exception or symbol . case TokenType.Character: return(new Syntax(new Value(thisToken.GetCharacter()), thisToken)); case TokenType.Boolean: return(new Syntax(new Value(thisToken.GetBool()), thisToken)); case TokenType.String: return(new Syntax(new Value(thisToken.GetString()), thisToken)); case TokenType.Symbol: return(new Syntax(thisToken.GetSymbol(), thisToken)); case TokenType.Heximal: case TokenType.Integer: return(new Syntax(new Value(thisToken.GetInteger()), thisToken)); case TokenType.Floating: return(new Syntax(new Value(thisToken.GetFloat()), thisToken)); case TokenType.OpenBracket: return(ParseList(thisToken, moreTokens)); case TokenType.OpenVector: return(ParseVector(thisToken, moreTokens)); case TokenType.Quote: case TokenType.Unquote: case TokenType.UnquoteSplicing: case TokenType.QuasiQuote: return(ParseQuoted(thisToken, moreTokens)); case TokenType.BadNumber: throw SchemeError.SyntaxError("parser", "looks like it should be a number, but it contains a syntax error", thisToken); default: // Unknown token type throw SchemeError.SyntaxError("parser", "the element is being used in a context where it is not understood", thisToken); } }
/// <summary> /// Parses a scheme expression in the default manner /// </summary> /// <returns>A scheme object</returns> /// <remarks>It is an error to pass scheme to this method with 'extraneous' tokens, such as trailing closing brackets</remarks> public static Syntax Parse(string scheme, string filepath) { var reader = new Tokenizer(new System.IO.StringReader(scheme), filepath); var res = Parse(reader); var token = reader.ReadToken(); if (token != null) { throw SchemeError.SyntaxError("parser", "found extra tokens after the end of a scheme expression", token); } return(res); }
/// <summary> /// Define new definition. /// </summary> /// <param name="name">identifier</param> /// <param name="binding">binding</param> public int Define(Symbol name, AstBinding binding) { var variable = LookupLocal(name); if (variable != null) { throw SchemeError.SyntaxError("define", "environment already have key", binding.Id); } binding.environment = this; binding.VarIdx = Bindings.Count; Bindings[name] = binding; return(binding.VarIdx); }
public char GetCharacter() { Debug.Assert(Type == TokenType.Character); if (Value.Length == 3) { return(System.Convert.ToChar(Value[2])); } else { var c = (char)0; if (CharType.NameToCharacter(Value, out c)) { return(c); } throw SchemeError.SyntaxError("get-character", "improperly formed char value", this); } }
public bool GetBool() { Debug.Assert(Type == TokenType.Boolean); if (Value == "#t") { return(true); } else if (Value == "#f") { return(false); } else { throw SchemeError.SyntaxError("get-bool", "improperly formed bool value", this); } }
public int GetInteger() { try { switch (Type) { case TokenType.Integer: return(StringLibs.GetInteger(Value)); case TokenType.Heximal: return(StringLibs.GetHexadecimal(Value)); default: throw SchemeError.SyntaxError("get-integer", "wrong token type", this); } } catch (System.Exception ex) { throw SchemeError.SyntaxError("get-integer", "improperly formed int value", this); } }
// retrieve a string literal token and advance our position private Token StringLiteral() { builder.Clear(); NextChar(); var type = TokenType.String; var matchingQuotes = false; while (Character >= 0) { // if we get an escape, increment the position some more and map the escaped character to what it should be if (Character == '\\') { NextChar(); builder.Append(MapEscaped(Character)); NextChar(); continue; } // unescaped quote? We're done with this string. if (Character == '"') { NextChar(); matchingQuotes = true; break; } builder.Append((char)Character); NextChar(); } // we didn't get opening and closing quotes :( if (!matchingQuotes) { throw SchemeError.SyntaxError("tokenizer", "unmatched quotes in string literal", lastToken); } return(DefineToken(type, builder.ToString())); }
// Expand string @syntax to abstract syntax tree, in given @env environment public static Ast ExpandInternal(Syntax syntax, Environment env) { if (syntax == null) { return(null); } else if (syntax.IsLiteral) { return(ExpandLiteral(syntax, env)); } else if (syntax.IsIdentifier) { return(ExpandIdentifier(syntax, env)); } else if (syntax.IsExpression) { return(ExpandExpression(syntax, env)); } else { throw SchemeError.SyntaxError("ast-builder-expand", "expected literal, identifier or list expression", syntax); } }
// retrieve a number literal token (int or decimal) and advance our position private Token NumberLiteral() { var type = TokenType.Integer; builder.Clear(); while (Character >= 0 && IsNumericalPart(Character)) { // if we get a decimal we're no longer working with an integer if (Character == '.') { if (type == TokenType.Floating) { throw SchemeError.SyntaxError("tokenizer", "error in numerical literal", lastToken); } type = TokenType.Floating; } builder.Append((char)Character); NextChar(); } return(DefineToken(type, builder.ToString())); }
private static Syntax ParseList(Token thisToken, Tokenizer moreTokens) { // Is a list/vector var listContents = new List <Syntax>(); Token dotToken = null; var nextToken = moreTokens.ReadToken(); while (nextToken != null && nextToken.Type != TokenType.CloseBracket) { // Parse this token listContents.Add(ParseToken(nextToken, moreTokens)); // Fetch the next token nextToken = moreTokens.ReadToken(); if (nextToken == null) { throw SchemeError.SyntaxError("parser", "Improperly formed list.", dotToken); } if (nextToken.Type == TokenType.Dot) { if (dotToken != null || thisToken.Type != TokenType.OpenBracket) { throw SchemeError.SyntaxError("parser", "Improperly formed dotted list", nextToken); } dotToken = nextToken; nextToken = moreTokens.ReadToken(); if (nextToken == null) { throw SchemeError.SyntaxError("parser", "Improperly formed dotted list", dotToken); } if (nextToken.Type == TokenType.CloseBracket) { throw SchemeError.SyntaxError("parser", "Improperly formed dotted list", dotToken); } listContents.Add(ParseToken(nextToken, moreTokens)); nextToken = moreTokens.ReadToken(); if (nextToken.Type != TokenType.CloseBracket) { throw SchemeError.SyntaxError("parser", "Improperly formed dotted list", dotToken); } break; } } if (nextToken == null) { // Missing ')' throw SchemeError.SyntaxError("parser", "missing close parenthesis", thisToken); } if (dotToken != null) { if (listContents.Count == 2) { return(new Syntax(new ValuePair(listContents[0], listContents[1]), thisToken)); } else { throw SchemeError.SyntaxError("parser", "improper dot syntax", thisToken); } } else { if (listContents.Count == 0) { return(new Syntax(Value.Nil, thisToken)); } else { return(new Syntax(ValueLinkedList.FromList <Syntax>(listContents), thisToken)); } } }
// (cond () ...) public static AST Expand(Syntax stx, Environment env) { var list = stx.AsLinkedList <Value>(); //< list of syntax objects var argc = GetArgsCount(list); var keyword = list[0].AsSyntax(); LinkedList <Value> allcases = null; LinkedList <Value> elsecase = null; var curent = list.GetNodeAtIndex(1); while (curent != null) { var conditional_stx = curent.Value.AsSyntax(); if (elsecase != null) { throw SchemeError.SyntaxError("cond", "unexpected expression after condition's else clause", conditional_stx); } if (conditional_stx.IsExpression) { // Get single conditional expression var conditional_list = conditional_stx.AsLinkedList <Value>(); // Check arguments count, should be 2 for each condition var size = conditional_list.Count; if (size != 2) { throw SchemeError.ArityError("cond", "arity mismatch", 2, size, conditional_list, conditional_stx); } // Now get condition and it's expression var var = conditional_list[0].AsSyntax(); var val = conditional_list[1].AsSyntax(); if (var.IsIdentifier && var.AsIdentifier() == Symbol.ELSE) { var ast = AstBuilder.ExpandInternal(val, env); elsecase = ValueLinkedList.FromArguments(new Value(var), new Value(ast)); } else { var cond_ = AstBuilder.ExpandInternal(var, env); var then_ = AstBuilder.ExpandInternal(val, env); var single_cond = ValueLinkedList.FromArguments(cond_, then_); if (allcases == null) { allcases = new LinkedList <Value>(); } allcases.AddLast(new Value(single_cond)); } } else { throw SchemeError.SyntaxError("cond", "Expected condition's expression list", conditional_stx); } curent = curent.Next; } return(new AstCondition(stx, keyword, allcases, elsecase)); }
/// <summary> /// The result structure has lists of arguments where /// the variable names as syntaxes, but initializers as AST /// </summary> /// <param name="expression">expression where this aregumens located</param> /// <param name="arguments">the arguments list (syntax syntax syntax ...)</param> /// <param name="env">environment</param> /// <param name="args">destination arguments structure</param> public static Environment ParseLambda(Syntax expression, LinkedList <Value> arguments, Environment environment) { var newenv = new Environment(environment, Symbol.NULL); if (arguments == null) { return(newenv); } var arg_type = ArgumentBinding.Type.Required; /// ---------------------------------------------------------------------- /// Waiting for the DSSSL keywords, when found change mode and return true /// ---------------------------------------------------------------------- Func <Syntax, bool> SymbolToArgumentType = (Syntax stx) => { if (!stx.IsSymbol) { return(false); } var symbol = stx.GetDatum().AsSymbol(); if (symbol == Symbol.OPTIONAL) { arg_type = ArgumentBinding.Type.Optionals; } else if (symbol == Symbol.KEY) { arg_type = ArgumentBinding.Type.Key; } else if (symbol == Symbol.REST) { arg_type = ArgumentBinding.Type.Rest; } else if (symbol == Symbol.BODY) { arg_type = ArgumentBinding.Type.Body; } else { return(false); } return(true); }; foreach (var arg in arguments) { var argstx = arg.AsSyntax(); if (!SymbolToArgumentType(argstx)) { switch (arg_type) { case ArgumentBinding.Type.Required: if (argstx.IsIdentifier) { ParseRequired("lambda", argstx, argstx, newenv, ArgumentBinding.Type.Required); } else { throw SchemeError.ArgumentError("lambda", "symbol?", argstx); } break; case ArgumentBinding.Type.Optionals: ParseOptional("lambda", argstx, argstx, newenv, ArgumentBinding.Type.Optionals); break; case ArgumentBinding.Type.Key: ParseOptional("lambda", argstx, argstx, newenv, ArgumentBinding.Type.Key); break; case ArgumentBinding.Type.Rest: ParseRequired("lambda", argstx, argstx, newenv, ArgumentBinding.Type.Rest); arg_type = ArgumentBinding.Type.End; break; case ArgumentBinding.Type.Body: ParseBody("lambda", argstx, argstx, newenv); arg_type = ArgumentBinding.Type.End; break; case ArgumentBinding.Type.End: throw SchemeError.SyntaxError("lambda", "unexpected extra argument", argstx); } } } return(newenv); }
// aka: x public static Ast ExpandIdentifier(Syntax syntax, Environment env) { if (!syntax.IsIdentifier) { throw SchemeError.SyntaxError("ast-builder-expand-identifier", "expected identifier", syntax); } var varname = (Name)syntax.GetDatum(); // Check and expand some of literals if (varname == EName.None) { return(new AstLiteral(syntax)); } // Find the variable in ast environment int envIdx = 0; var binding = env.LookupAstRecursively(varname, ref envIdx); if (binding == null) { // If variable is not found designate it as global variable var localIdx = env.Define(varname, new GlobalBinding(syntax)); return(new AstReference(syntax, AstReferenceType.Global, localIdx)); } else { if (envIdx == 0) { // local variable reference return(new AstReference(syntax, AstReferenceType.Local, binding.VarIdx, 0, 0)); } else { // up-value reference if (binding is GlobalBinding || !binding.environment.IsLexical) { // global variable var localIdx = env.Define(varname, new GlobalBinding(syntax)); return(new AstReference(syntax, AstReferenceType.Global, localIdx)); } else if (binding is LocalBinding || binding is ArgumentBinding) { // up value to local variable var localIdx = env.Define(varname, new UpBinding(syntax, envIdx, binding.VarIdx)); return(new AstReference(syntax, AstReferenceType.UpValue, localIdx, envIdx, binding.VarIdx)); } else if (binding is UpBinding) { // upValue to other upValue var upBinding = binding as UpBinding; var nEnvIdx = upBinding.UpEnvIdx + envIdx; var nVarIdx = upBinding.UpVarIdx; var localIdx = env.Define(varname, new UpBinding(syntax, nEnvIdx, nVarIdx)); return(new AstReference(syntax, AstReferenceType.UpValue, localIdx, nEnvIdx, nVarIdx)); } else { throw new SystemException(); } } } }
// retrieve a vector literal marker, boolean token, or character literal token and advance our position private Token VectorOrBooleanOrChar() { builder.Clear(); var boolLiterals = new List <char> { 'F', 'f', 't', 'T' }; var nextc = reader.Peek(); if (boolLiterals.Contains((char)nextc)) { // boolean literal! builder.Append((char)Character); NextChar(); // skip # if (Character >= 0) { builder.Append((char)Character); NextChar(); // skip F,f,t,T } return(DefineToken(TokenType.Boolean, builder.ToString())); } else if (nextc == '(') { // vector literal! NextChar(); // skip # NextChar(); // skip ( return(DefineToken(TokenType.OpenVector, "(")); } else if (nextc == '\\') { // char literal! while (Character >= 0 && !IsWhitespace(Character)) { if (builder.Size < 3) { builder.Append((char)Character); NextChar(); } else { if (!IsEOF(Character) && IsSymbolPart(Character)) { builder.Append((char)Character); NextChar(); } else { break; } } } return(DefineToken(TokenType.Character, builder.ToString())); } else if (nextc == 'x') { builder.Append((char)Character); NextChar(); // skip # builder.Append((char)Character); NextChar(); // skip x // char literal! while (Character >= 0 && IsHeximalPart(Character)) { builder.Append((char)Character); NextChar(); } return(DefineToken(TokenType.Heximal, builder.ToString())); } //else if (nextc == '!') //{ // builder.Append((char)Character); // NextChar(); // skip # // builder.Append((char)Character); // NextChar(); // skip ! // // char literal! // while (Character >= 0 && IsSymbolPart(Character)) // { // builder.Append((char)Character); // NextChar(); // } // return DefineToken(TokenType.Symbol, builder.ToString()); //} else { throw SchemeError.SyntaxError("tokenizer", "inside '#' but no matching characters to construct a token", lastToken); } }