public static Expression CompileLetSymbolMacro(Cons form, AnalysisScope scope) { // let-symbol-macro name form CheckLength(form, 3); CheckMinLength(form, 3); var sym = CheckSymbol(Second(form)); if (sym.IsDynamic) { throw new LispException("Invalid symbol-macro name: {0}", sym); } if (!scope.IsBlockScope) { throw new LispException("Statement requires block or file scope: {0}", form); } if (sym == Symbols.Tilde) { throw new LispException("\"~\" is a reserved symbol name"); } if (scope.FindDuplicate(sym)) { throw new LispException("Duplicate declaration of variable: {0}", sym); } var macro = new SymbolMacro(Third(form)); scope.DefineMacro(sym, macro, ScopeFlags.SymbolMacro | ScopeFlags.All); return Expression.Constant(null); }
public static Expression CompileLexicalVarInScope(Cons form, AnalysisScope scope, bool native, bool future, bool lazy, bool constant) { // var sym [expr] var sym = (Symbol)Second(form); var initForm = Third(form); if (!scope.IsBlockScope) { throw new LispException("Statement requires block or file scope: {0}", form); } if (sym == Symbols.Tilde) { throw new LispException("\"~\" is a reserved symbol name"); } if (scope.FindDuplicate(sym)) { throw new LispException("Duplicate declaration of variable: {0}", sym); } constant |= future | lazy; // Initializer must be compiled before adding the variable // since it may already exist. Works like nested LET forms. var flags = (ScopeFlags)0; Expression val; if (Length(form) == 2) { if (constant) { throw new LispException("Constant, future or lazy variable must have an initializer: {0}", form); } val = CompileLiteral(null); } else { flags |= ScopeFlags.Initialized | (constant ? ScopeFlags.Constant : 0); if (lazy && future) { // Wrap initializer in TASK macro and wrap references to the variable in a // GetTaskResult call (see CompileGetVariable). flags |= ScopeFlags.Lazy | ScopeFlags.Future; val = Compile(MakeList(Symbols.CreateTask, MakeList(Symbols.Lambda, null, initForm), false), scope); } else if (lazy) { // Wrap initializer in DELAY macro and wrap references to the variable in a // FORCE call. flags |= ScopeFlags.Lazy; val = Compile(MakeList(MakeSymbol("system:create-delayed-expression"), MakeList(Symbols.Lambda, null, initForm)), scope); } else if (future) { // Wrap initializer in TASK macro and wrap references to the variable in a // GetTaskResult call (see CompileGetVariable). flags |= ScopeFlags.Future; val = Compile(MakeList(Symbols.CreateTask, MakeList(Symbols.Lambda, null, initForm), true), scope); } else { val = Compile(initForm, scope); } } if (scope.IsFileScope) { int index = scope.DefineFrameLocal(sym, flags); return CallRuntime(SetLexicalMethod, Expression.Constant(0), Expression.Constant(index), val); } else if (native) { var parameter = scope.DefineNativeLocal(sym, flags); return Expression.Assign(parameter, val); } else if (!DebugMode && scope.FreeVariables != null && !scope.FreeVariables.Contains(sym)) { var parameter = scope.DefineNativeLocal(sym, flags); return Expression.Assign(parameter, val); } else { int index = scope.DefineFrameLocal(sym, flags); return CallRuntime(SetLexicalMethod, Expression.Constant(0), Expression.Constant(index), val); } }
public static Expression CompileLetMacro(Cons form, AnalysisScope scope) { // letmacro name args body CheckMinLength(form, 3); var sym = CheckSymbol(Second(form)); if (sym.IsDynamic) { throw new LispException("Invalid macro name: {0}", sym); } if (!scope.IsBlockScope) { throw new LispException("Statement requires block or file scope: {0}", form); } if (sym == Symbols.Tilde) { throw new LispException("\"~\" is a reserved symbol name"); } if (scope.FindDuplicate(sym)) { throw new LispException("Duplicate declaration of variable: {0}", sym); } string doc; var lambda = CompileLambdaDef(sym, Cddr(form), scope, LambdaKind.Macro, out doc); var closure = (LambdaClosure)Execute(lambda); scope.DefineMacro(sym, closure, ScopeFlags.Macro | ScopeFlags.All); return Expression.Constant(null); }