public static ScriptObject ParseChar(ParseState state) { var result = new GenericScriptObject("@type", "char", "@start", state.start, "@source", state); var token = ""; state.Advance(); //skip opening ' while (!state.AtEnd()) { if (state.Next() == '\\') { state.Advance(); if (state.Next() == 'n') token += "\n"; if (state.Next() == 't') token += "\t"; if (state.Next() == 'r') token += "\r"; else token += state.Next(); } else if (state.Next() == '\'') { result["@end"] = state.start; result["@token"] = token; state.Advance(); return result; } else { token += state.Next(); state.Advance(); } } result["@end"] = state.start; result["@token"] = token; return result; }
public static int ParseComment(ParseState state) { var start = state.start; state.Advance(2); while (!state.AtEnd() && !state.MatchNext("*/")) state.Advance(); state.Advance(2); return state.start - start; }
public static ParseNode ParseExpression(ParseState state) { ParseNode result = null; var prefix = ParsePrefix(state); if (state.Next() == '[') //Dictionary Entry { result = ParseNode(state, "[", "]"); result.type = NodeType.DictionaryEntry; } else if (state.Next() == '"') { result = ParseStringExpression(state); //if (prefix == Prefix.Quote) // result = new ParseNode(NodeType.String, result.start, state) // { // token = state.source.Substring(result.start + 1, result.end - result.start - 2) // }; } else if (state.Next() == '(') { result = ParseNode(state); } else if ("-0123456789".Contains(state.Next())) { result = ParseNumber(state); } //else if (!state.AtEnd() && " \t\r\n".Contains(state.Next())) //prefix followed by space?? //{ // if (prefix != Prefix.None) //rewind prefix // { // prefix = Prefix.None; // state.start -= 1; // } // result = ParseToken(state); //} else { result = ParseToken(state); } if (state.Next() == '.' || state.Next() == ':') { var final_result = new ParseNode(NodeType.MemberAccess, result.start, state); final_result.childNodes.Add(result); final_result.token = new String(state.Next(), 1); state.Advance(); final_result.childNodes.Add(ParseExpression(state)); result = final_result; } result.prefix = prefix; if (!PrefixCheck.CheckPrefix(result)) throw new ParseError("Illegal prefix on expression of type " + result.type, state.currentLine); return result; }
public static void DevourWhitespace(ParseState state) { while (!state.AtEnd() && " \t\r\n".Contains(state.Next())) state.Advance(); }
public static ParseNode ParseStringExpression(ParseState state, bool isRoot = false) { var result = new ParseNode(NodeType.StringExpression, state.start, state); if (!isRoot) state.Advance(); //Skip opening quote string piece = ""; int piece_start = state.start; while (!state.AtEnd()) { if (state.Next() == '(') { if (piece.Length > 0) result.childNodes.Add(new ParseNode(NodeType.String, piece_start, state) { token = state.source.Substring(piece_start, state.start - piece_start) }); result.childNodes.Add(ParseNode(state)); piece = ""; } else if (state.Next() == '\\') { if (piece.Length == 0) piece_start = state.start; state.Advance(); //skip the slash. piece += "\\" + state.Next(); state.Advance(); } else if (!isRoot && state.Next() == '"') { if (piece.Length > 0) result.childNodes.Add(new ParseNode(NodeType.String, piece_start, state) { token = state.source.Substring(piece_start, state.start - piece_start) }); state.Advance(); result.end = state.start; if (result.childNodes.Count == 1 && result.childNodes[0].type == NodeType.String) return result.childNodes[0]; return result; } else { if (piece.Length == 0) piece_start = state.start; piece += state.Next(); state.Advance(); } } if (isRoot) { if (piece.Length > 0) result.childNodes.Add(new ParseNode(NodeType.String, piece_start, state) { token = state.source.Substring(piece_start, state.start - piece_start) }); if (result.childNodes.Count == 1) return result.childNodes[0]; return result; } throw new ParseError("Unexpected end of script inside string expression.", state.currentLine); }
public static ParseNode ParseToken(ParseState state) { var result = new ParseNode(NodeType.Token, state.start, state); while (!state.AtEnd() && !(" \t\r\n:.)]".Contains(state.Next()))) state.Advance(); result.end = state.start; result.token = state.source.Substring(result.start, result.end - result.start); if (String.IsNullOrEmpty(result.token)) throw new ParseError("Empty token", state.currentLine); return result; }
public static Prefix ParsePrefix(ParseState state) { Prefix result = Prefix.None; if (state.Next() == '*') result = Prefix.Quote; else if (state.Next() == '^') result = Prefix.List; else if (state.Next() == '$') result = Prefix.Expand; else if (state.Next() == '#') result = Prefix.Lookup; else if (state.Next() == ':') result = Prefix.Evaluate; if (result != Prefix.None) state.Advance(); return result; }
public static ParseNode ParseRoot(String script, String filename) { var commentFree = ""; var state = new ParseState { start = 0, end = script.Length, source = script, filename = filename }; while (!state.AtEnd()) { if (state.MatchNext("/*")) commentFree += (new String(' ',ParseComment(state))); else { commentFree += state.Next(); state.Advance(); } } return ParseStringExpression(new ParseState { start = 0, end = commentFree.Length, source = commentFree, filename = filename }, true); }
public static ParseNode ParseNode(ParseState state, String start = "(", String end = ")") { var result = new ParseNode(NodeType.Node, state.start, state); if (!state.MatchNext(start)) throw new ParseError("Expected " + start, state.currentLine); state.Advance(start.Length); while (!state.MatchNext(end)) { DevourWhitespace(state); if (!state.MatchNext(end)) { var expression = ParseExpression(state); if (expression.type == NodeType.MemberAccess) expression = ReorderMemberAccessNode(expression); result.childNodes.Add(expression); } DevourWhitespace(state); } state.Advance(end.Length); return result; }
public static ParseNode ParseNumber(ParseState state) { var result = new ParseNode(NodeType.Number, state.start, state); bool foundDot = false; while (!state.AtEnd()) { if (state.Next() == '-') { if (result.start != state.start) break; state.Advance(); continue; } if (state.Next() >= '0' && state.Next() <= '9') { state.Advance(); continue; } else if (state.Next() == '.') { if (foundDot) break; foundDot = true; state.Advance(); continue; } break; } result.end = state.start; result.token = state.source.Substring(result.start, result.end - result.start); return result; }
public static ScriptObject ParseNode(ParseState state, String start = "(", String end = ")") { var result = new GenericScriptObject("@type", "node", "@start", state.start, "@source", state); if (!state.MatchNext(start)) throw new ParseError("Expected " + start, state.currentLine); state.Advance(start.Length); while (!state.AtEnd() && !state.MatchNext(end)) { DevourWhitespace(state); if (state.Next() == '}') return result; if (!state.AtEnd() && !state.MatchNext(end)) { var expression = ParseExpression(state); if (isType(expression, "memberaccess")) expression = ReorderMemberAccessNode(expression); children(result).Add(expression); } DevourWhitespace(state); } if (end != null) state.Advance(end.Length); return result; }
public static ScriptObject ParseStringExpression(ParseState state, bool isRoot = false) { var result = new GenericScriptObject("@type", "stringexpression", "@start", state.start, "@source", state); if (!isRoot) { state.Advance(); //Skip opening quote } string piece = ""; int piece_start = state.start; while (!state.AtEnd()) { if (state.Next() == '}' && piece.Length == 0) { state.Advance(1); } else if (state.Next() == '(') { if (piece.Length > 0) { children(result).Add( new GenericScriptObject("@type", "string", "@start", piece_start, "@source", state, "@token", state.source.Substring(piece_start, state.start - piece_start))); } children(result).Add(ParseNode(state)); piece = ""; } else if (state.Next() == '\\') { if (piece.Length == 0) { piece_start = state.start; } state.Advance(); //skip the slash. piece += state.Next(); state.Advance(); } else if (!isRoot && state.Next() == '"') { if (piece.Length > 0) { children(result).Add( new GenericScriptObject("@type", "string", "@start", piece_start, "@source", state, "@token", state.source.Substring(piece_start, state.start - piece_start))); } state.Advance(); result["@end"] = state.start; if (children(result).Count == 1 && isType(children(result)[0] as ScriptObject, "string")) { return(child(result, 0) as ScriptObject); } return(result); } else { if (piece.Length == 0) { piece_start = state.start; } piece += state.Next(); state.Advance(); } } if (isRoot) { if (piece.Length > 0) { children(result).Add(new GenericScriptObject("@type", "string", "@start", piece_start, "@source", state, "@token", state.source.Substring(piece_start, state.start - piece_start))); } if (children(result).Count == 1) { return(child(result, 0) as ScriptObject); } return(result); } throw new ParseError("Unexpected end of script inside string expression.", state.currentLine); }
public static ScriptObject ParseToken(ParseState state) { var result = new GenericScriptObject("@type", "token", "@start", state.start, "@source", state); while (!state.AtEnd() && !(" \t\r\n:.)]}".Contains(state.Next()))) state.Advance(); result["@end"] = state.start; result["@token"] = state.source.Substring(asInt(result["@start"]), asInt(result["@end"]) - asInt(result["@start"])); if (String.IsNullOrEmpty(result.gsp("@token"))) throw new ParseError("Empty token", state.currentLine); return result; }
public static ScriptObject ParseStringExpression(ParseState state, bool isRoot = false) { var result = new GenericScriptObject("@type", "stringexpression", "@start", state.start, "@source", state); if (!isRoot) state.Advance(); //Skip opening quote string piece = ""; int piece_start = state.start; while (!state.AtEnd()) { if (state.Next() == '}' && piece.Length == 0) { state.Advance(1); } else if (state.Next() == '(') { if (piece.Length > 0) children(result).Add( new GenericScriptObject("@type", "string", "@start", piece_start, "@source", state, "@token", state.source.Substring(piece_start, state.start - piece_start))); children(result).Add(ParseNode(state)); piece = ""; } else if (state.Next() == '\\') { if (piece.Length == 0) piece_start = state.start; state.Advance(); //skip the slash. piece += state.Next(); state.Advance(); } else if (!isRoot && state.Next() == '"') { if (piece.Length > 0) children(result).Add( new GenericScriptObject("@type", "string", "@start", piece_start, "@source", state, "@token", state.source.Substring(piece_start, state.start - piece_start))); state.Advance(); result["@end"] = state.start; if (children(result).Count == 1 && isType(children(result)[0] as ScriptObject, "string")) return child(result, 0) as ScriptObject; return result; } else { if (piece.Length == 0) piece_start = state.start; piece += state.Next(); state.Advance(); } } if (isRoot) { if (piece.Length > 0) children(result).Add(new GenericScriptObject("@type", "string", "@start", piece_start, "@source", state, "@token", state.source.Substring(piece_start, state.start - piece_start))); if (children(result).Count == 1) return child(result, 0) as ScriptObject; return result; } throw new ParseError("Unexpected end of script inside string expression.", state.currentLine); }
public static ScriptObject ParseRoot(String script, String filename) { var commentFree = new StringBuilder(); var state = new ParseState { start = 0, end = script.Length, source = script, filename = filename }; while (!state.AtEnd()) { if (state.MatchNext("/*")) commentFree.Append(new String(' ',ParseComment(state))); else { commentFree.Append(state.Next()); state.Advance(); } } var r = ParseNode( new ParseState { start = 0, end = commentFree.Length, source = commentFree.ToString(), filename = filename }, "", null); if (r._children.Count == 1) return r._child(0) as ScriptObject; r.SetProperty("@type", "root"); return r; }
public static String ParsePrefix(ParseState state) { var next = state.Next(); if (next == '*' || next == '^' || next == '$' || next == '.' || next == ':') { state.Advance(); return new String(next, 1); } return ""; }
public static ScriptObject ParseNumber(ParseState state) { var result = new GenericScriptObject("@type", "number", "@start", state.start, "@source", state); bool foundDot = false; while (!state.AtEnd()) { if (state.Next() == '-') { if (asInt(result["@start"]) != state.start) break; state.Advance(); continue; } if (state.Next() >= '0' && state.Next() <= '9') { state.Advance(); continue; } else if (state.Next() == '.') { if (foundDot) break; foundDot = true; state.Advance(); continue; } break; } result["@end"] = state.start; result["@token"] = state.source.Substring(asInt(result["@start"]), asInt(result["@end"]) - asInt(result["@start"])); return result; }
public static ScriptObject ParseExpression(ParseState state) { ScriptObject result = null; var prefix = ParsePrefix(state); if (state.Next() == '"') { result = ParseStringExpression(state); } else if (state.Next() == '(') { result = ParseNode(state); } else if (state.Next() == '\'') { result = ParseChar(state); } else if ("-0123456789".Contains(state.Next())) { result = ParseNumber(state); if (result["@token"].ToString() == "-") //A lone - sign is not a valid number. Interpret it as a token. result["@type"] = "token"; } else { if (" \t\r\n:.)}".Contains(state.Next()) && !String.IsNullOrEmpty(prefix)) { //The prefix is a token. result = new GenericScriptObject("@type", "token", "@start", state.start - 1, "@source", state); result["@end"] = state.start; result["@token"] = prefix; prefix = ""; } else result = ParseToken(state); } if (!state.AtEnd() && (state.Next() == '.' || state.Next() == ':')) { var final_result = new GenericScriptObject("@type", "memberaccess", "@start", result["@start"], "@source", state); children(final_result).Add(result); final_result["@token"] = new String(state.Next(), 1); state.Advance(); children(final_result).Add(ParseExpression(state)); result = final_result; } result["@prefix"] = prefix; if (!PrefixCheck.CheckPrefix(result)) throw new ParseError("Illegal prefix on expression of type " + result["@type"], state.currentLine); return result; }
public static ScriptObject ParseExpression(ParseState state) { ScriptObject result = null; var prefix = ParsePrefix(state); if (state.Next() == '"') { if (prefix == "$") { prefix = ""; result = ParseBasicString(state); } else { result = ParseStringExpression(state); } } else if (state.Next() == '(') { result = ParseNode(state); } else if (state.Next() == '\'') { result = ParseChar(state); } else if ("-0123456789".Contains(state.Next())) { result = ParseNumber(state); if (result["@token"].ToString() == "-") //A lone - sign is not a valid number. Interpret it as a token. { result["@type"] = "token"; } } else { if (" \t\r\n:.)}".Contains(state.Next()) && !String.IsNullOrEmpty(prefix)) { //The prefix is a token. result = new GenericScriptObject("@type", "token", "@start", state.start - 1, "@source", state); result["@end"] = state.start; result["@token"] = prefix; prefix = ""; } else { result = ParseToken(state); } } if (!state.AtEnd() && (state.Next() == '.' || state.Next() == ':')) { var final_result = new GenericScriptObject("@type", "memberaccess", "@start", result["@start"], "@source", state); children(final_result).Add(result); final_result["@token"] = new String(state.Next(), 1); state.Advance(); children(final_result).Add(ParseExpression(state)); result = final_result; } result["@prefix"] = prefix; if (!PrefixCheck.CheckPrefix(result)) { throw new ParseError("Illegal prefix on expression of type " + result["@type"], state.currentLine); } return(result); }