private object EX_While(LispRuntimeCommand cmd, LispList program) { object retVal = null; if (program.items.Count < 2) { throw new LispParseException($"'{cmd.CommandName}' command must have at least 1 parameter. Line: {program.line}:{program.position}"); } LispItem conditionalStatement = program.items[1]; // body of the while loop start: object conditionalResult = Run(conditionalStatement); CheckParameterType(cmd, 1, program, conditionalResult, typeof(bool), false); if ((bool)conditionalResult) { for (int i = 2; i < program.items.Count; i++) { retVal = Run(program.items[i]); } goto start; } return(retVal); }
private object EX_If(LispRuntimeCommand cmd, LispList program) { CheckParameterCount(cmd, program, 2, 3); LispItem conditionalStatement = program.items[1]; LispItem trueStatement = program.items[2]; // run the condition object conditionResult = Run(conditionalStatement); CheckParameterType(cmd, 1, program, conditionResult, typeof(bool), false); if ((bool)conditionResult) { return(Run(trueStatement)); } else if (program.items.Count == 4) { LispItem falseStatement = program.items[3]; return(Run(falseStatement)); } else { return(null); } }
private object EX_Not(LispRuntimeCommand cmd, LispList program) { CheckParameterCount(cmd, program, 1); object result = Run(program.items[1]); CheckParameterType(cmd, 1, program, result, typeof(bool), false); return(!((bool)result)); }
private object Ex_LessThanEqual(LispRuntimeCommand cmd, LispList program) { CheckParameterCount(cmd, program, 2); long a = GetLongValue(cmd, program, 1, false); long b = GetLongValue(cmd, program, 2, false); return(a <= b); }
public object RunList(LispList program) { object result = null; LispItem first = program.items.First(); if (first is LispSymbol) { try { LispSymbol sym = first as LispSymbol; LispRuntimeCommand cmd; if (_commands.TryGetValue(sym.name, out cmd)) { result = cmd.Command(cmd, program); _logger.LogIf(_categories.ScriptLogging, Level.Debug, $"Run {first.line}:{first.position} Cmd:{cmd.CommandName}==>{(result ?? (object)"null")}"); } else { throw new LispParseException($"Unknown command symbol '{sym.name}' Line: {sym.line}:{sym.position}"); } } catch (Exception ex) { if (!(ex is LispParseException)) { throw new LispParseException($"{ex.Message} Line {first.line}:{first.position}", ex); } else { throw; } } } else if (first is LispList) { foreach (LispItem item in program.items) { if (item is LispList) { result = Run(item as LispList); } else { throw new LispParseException($"Expected a LispList but got a {item.GetType().Name} Line: {item.line}:{item.position}"); } } } else { throw new LispParseException($"Can only execute lists and symbols. Line: {first.line}:{first.position}"); } return(result); }
private object Ex_GetArg(LispRuntimeCommand cmd, LispList list) { CheckParameterCount(cmd, list, 1, 2); string arg = Run <string>(list.items[1]); object defaultValue = null; if (list.items.Count > 2) { defaultValue = Run <object>(list.items[2]); } else { defaultValue = string.Empty; } var args = Environment.GetCommandLineArgs(); string returnValue = null; for (int i = 0; i < args.Length; i++) { var a = args[i]; if (a == arg) { if (i + 1 < args.Length) { returnValue = args[i + 1]; } else { break; } } } if (returnValue == null) { return(defaultValue); } switch (defaultValue) { case double d: return(double.Parse(returnValue)); case int i: return(int.Parse(returnValue)); default: return(returnValue); } }
private object Ex_Assert(LispRuntimeCommand cmd, LispList list) { CheckParameterCount(cmd, list, 1); bool isOkay = Run <bool>(list.items[1]); if (isOkay) { return(true); } else { throw new Exception($"Failed Assert on {list.line}:{list.position}"); } }
protected long GetLongValue(LispRuntimeCommand cmd, LispList program, int index, bool allowNull) { object v = Run(program.items[index]); CheckParameterType(cmd, index, program, v, typeof(long), allowNull); if (null == v) { return(0); } else { return((long)v); } }
protected static void CheckParameterCount(LispRuntimeCommand cmd, LispList program, params int[] expectedCounts) { if (!expectedCounts.Contains(program.items.Count - 1)) { if (expectedCounts.Length == 1) { throw new LispParseException($"'{cmd.CommandName}' command must have exactly {expectedCounts[0]} parameters. Line: {program.line}:{program.position}"); } else { throw new LispParseException($"'{cmd.CommandName}' command expects {expectedCounts.ToDelimited("","", " or ")} parameters. Line: {program.line}:{program.position}"); } } }
private object EX_SetVariable(LispRuntimeCommand cmd, LispList program) { CheckParameterCount(cmd, program, 2); // get parameters string variableName = Run(program.items[1]) as string; object variableValue = Run(program.items[2]); CheckParameterType(cmd, 1, program, variableName, typeof(string), false); _var[variableName] = variableValue; return(variableValue); }
public static void Execute(LispList program, Dictionary <string, string> environmentVariables, ILogger logger, ICategories categories) { LispExecuter executer = new LispExecuter(logger, categories); executer.SetEnvironment(environmentVariables); try { executer.Run <object>(program); } catch (Exception ex) { Console.WriteLine("Error: {0}", ex.Message); } }
private object Ex_Or(LispRuntimeCommand cmd, LispList program) { CheckParameterCount(cmd, program, 2); object leftResult = Run(program.items[1]); CheckParameterType(cmd, 1, program, leftResult, typeof(bool), false); if ((bool)leftResult) { return(true); } object rightResult = Run(program.items[2]); CheckParameterType(cmd, 2, program, leftResult, typeof(bool), false); return((bool)rightResult); }
private object Ex_Sub(LispRuntimeCommand cmd, LispList program) { if (program.items.Count - 1 < 2) { throw new LispParseException($"'{cmd.CommandName}' command must have at least 2 parameters. Line: {program.line}:{program.position}"); } long accumulator = GetLongValue(cmd, program, 1, false); for (int i = 2; i < program.items.Count; i++) { long number = GetLongValue(cmd, program, i, false); accumulator -= number; } return(accumulator); }
private object EX_GetVariableMember(LispRuntimeCommand cmd, LispList program) { CheckParameterCount(cmd, program, 2); int c = 1; object instance = Run(program.items[c++]); string name = Run <string>(program.items[c++]); var member = instance.GetType().GetMember(name)[0]; switch (member) { case PropertyInfo property: return(property.GetValue(instance)); case FieldInfo field: return(field.GetValue(instance)); } return(null); }
private object EX_Equal(LispRuntimeCommand cmd, LispList program) { CheckParameterCount(cmd, program, 2); object value1 = Run(program.items[1]); object value2 = Run(program.items[2]); if (value1 == value2) { return(true); } if (value1 != null) { return(value1.Equals(value2)); } return(false); }
private object EX_GetEnvironment(LispRuntimeCommand cmd, LispList program) { CheckParameterCount(cmd, program, 1); string variableName = Run(program.items[1]) as string; CheckParameterType(cmd, 1, program, variableName, typeof(string), false); string value = null; if (_env.TryGetValue(variableName, out value)) { return(value); } else { var item = program.items[1]; throw new LispParseException($"GetEnvironment command failed. Variable '{variableName}' doesn't exist. Line: {item.line}:{item.position}"); } }
private object EX_Loop(LispRuntimeCommand cmd, LispList program) { object retVal = null; if (program.items.Count < 3) { throw new LispParseException($"'{cmd.CommandName}' command must have at least 2 parameters. Line: {program.line}:{program.position}"); } long loopCount = GetLongValue(cmd, program, 1, false); for (long i = 0; i < loopCount; i++) { for (int j = 2; j < program.items.Count; j++) { retVal = Run(program.items[j]); } } return(retVal); }
private object Ex_ForEach(LispRuntimeCommand cmd, LispList list) { if (list.items.Count < 3) { throw new LispParseException($"'{cmd.CommandName}' command expects more than 1 parameters. Line: {list.line}:{list.position}"); } string variableName = Run <string>(list.items[1]); string[] loopItems = Run <string[]>(list.items[2]); foreach (string variableValue in loopItems) { SetVariable(variableName, variableValue); for (int i = 2; i < list.items.Count; i++) { Run(list.items[i]); } } return(null); }
internal LispList(List <LispToken> tokens, ref int index) { Init(); if (index >= tokens.Count) { throw new LispParseException("Consturctor called but no tokens to parse!"); } // check for left paranthesies LispToken token = tokens[index]; if (token.type != TokenType.ParamLeft) { throw new LispParseException($"Lisp List must start with a left parantheses. Line {token.line}:{token.position}"); } bool notFoundEnd = true; index++; for (; index < tokens.Count && notFoundEnd; index++) { token = tokens[index]; switch (token.type) { case TokenType.ParamLeft: LispList lst = new LispList(tokens, ref index); lst.line = token.line; lst.position = token.position; items.Add(lst); break; case TokenType.ParamRight: notFoundEnd = false; index--; break; case TokenType.Double: items.Add(new LispDouble() { value = (double)token.lValue, line = token.line, position = token.position }); break; case TokenType.Int: items.Add(new LispInt() { value = (int)token.lValue, line = token.line, position = token.position }); break; case TokenType.String: items.Add(new LispString() { value = token.value, line = token.line, position = token.position }); break; case TokenType.Symbol: items.Add(new LispSymbol() { name = token.value, line = token.line, position = token.position }); break; } } }
protected static void CheckParameterType(LispRuntimeCommand cmd, int paramIndex, LispList program, object item, Type expectedType, bool allowNull) { if (null == item) { if (allowNull) { return; } else { throw new Exception(string.Format("'{0}' parameter {1} cannot be null. Line: {2}:{3}", cmd.CommandName, paramIndex, program.line, program.position)); } } if (item.GetType() != expectedType) { throw new Exception(string.Format("'{0}' expected parameter {1} to be of type {2}. Line: {3}:{4}", cmd.CommandName, paramIndex, expectedType, program.line, program.position)); } }
private object Ex_Array(LispRuntimeCommand cmd, LispList list) { return(list.items.Skip(1).Select(i => Run <string>(i)).ToArray()); }
public static LispList Parse(string lispString) { int line = 1; int position = 0; List <LispToken> tokens = new List <LispToken>(); // tokenize the string for (int i = 0; i < lispString.Length; i++) { char c = lispString[i]; position++; if (c == '\n') { line++; position = 1; } if (char.IsWhiteSpace(c)) { continue; } switch (c) { case '#': case ';': // eat the comment comment until we find a new line. int newIndex = lispString.IndexOf('\n', i); if (newIndex > 0) { i = newIndex - 1; } else { i = lispString.Length; } break; case '(': tokens.Add(new LispToken() { type = TokenType.ParamLeft, line = line, position = position }); break; case ')': tokens.Add(new LispToken() { type = TokenType.ParamRight, line = line, position = position }); break; case '"': { int index; bool isClosed = false; for (index = i + 1; index < lispString.Length && !isClosed; index++) { char cc = lispString[index]; switch (cc) { case '"': isClosed = true; index--; break; case '\n': throw new LispParseException($"String literal cannot contain a carriage return. Line {line}:{position}"); } } if (isClosed) { tokens.Add(new LispToken() { type = TokenType.String, value = lispString.Substring(i + 1, (index - 1) - i), line = line, position = position }); i = index; } else { throw new LispParseException($"String not closed on line {line}:{position}"); } } break; default: { if (char.IsLetter(c)) { // it's a symbol int index; for (index = i; index < lispString.Length; index++) { char cc = lispString[index]; if (!char.IsLetterOrDigit(cc)) { break; } } tokens.Add(new LispToken() { type = TokenType.Symbol, value = lispString.Substring(i, index - i), line = line, position = position }); position += (index - 1) - i; i = index - 1; } else if (char.IsDigit(c) || c == '.') { // it's a number int index; for (index = i; index < lispString.Length; index++) { char cc = lispString[index]; if (!(char.IsLetterOrDigit(cc) || cc == '.')) { break; } } char typeValue = lispString[index - 1]; string strValue = lispString.Substring(i, index - i - 1); switch (typeValue) { case 'd': { double lValue; if (double.TryParse(strValue, out lValue)) { tokens.Add(new LispToken() { type = TokenType.Double, value = strValue, lValue = lValue, line = line, position = position }); } else { throw new LispParseException($"Not a valid double. Line: {line}:{position}"); } break; } case 'i': { int lValue; if (int.TryParse(strValue, out lValue)) { tokens.Add(new LispToken() { type = TokenType.Int, value = strValue, lValue = lValue, line = line, position = position }); } else { throw new LispParseException($"Not a valid int. Line: {line}:{position}"); } } break; default: throw new LispParseException($"Not a valid number type. Line:{line},{position}"); } position += (index - 1) - i; i = index - 1; } } break; } } // was there any tokens? if (tokens.Count == 0) { throw new Exception("Nothing parsable in the file!"); } // perform balance check if (0 != tokens.Sum(t => ((t.type == TokenType.ParamLeft) ? 1 : (t.type == TokenType.ParamRight) ? -1 : 0))) { throw new LispParseException("Parathensies aren't balanced."); } int token_index = 0; LispList root = new LispList(tokens, ref token_index); return(root); }