public override IBELObject ValueOf(string name, System.Collections.ArrayList arguments, ExecutionContext ctx) { Hashtable members = ctx.CurrentFederation.GetTopicProperties(Name); string val = (string)(members[name]); if (val == null) return null; val = val.Trim(); bool isBlock = val.StartsWith("{"); if (!isBlock) return new BELString(val); // It's a block, so fire up the interpreter if (!val.EndsWith("}")) throw new ExecutionException("Topic member " + name + " defined in " + Name.Fullname + " is not well-formed; missing closing '}' for code block."); ContentBase cb = CurrentFederation.ContentBaseForTopic(Name); TopicContext newContext = new TopicContext(ctx.CurrentFederation, cb, CurrentTopicInfo); BehaviorInterpreter interpreter = new BehaviorInterpreter(val, CurrentFederation, CurrentFederation.WikiTalkVersion, ctx.Presenter); if (!interpreter.Parse()) throw new ExecutionException("Parsing error evaluating topic member " + name + " defined in " + Name.Fullname + ": " + interpreter.ErrorString); IBELObject b1 = interpreter.EvaluateToObject(newContext, ctx.ExternalWikiMap); if (b1 == null) throw new ExecutionException("Error while evaluating topic member " + name + " defined in " + Name.Fullname + ": " + interpreter.ErrorString); Block block = (Block)b1; ArrayList evaluatedArgs = new ArrayList(); foreach (object each in arguments) { IBELObject add = null; if (each != null && each is IBELObject) add = each as IBELObject; else { ExposableParseTreeNode ptn = each as ExposableParseTreeNode; add = ptn.Expose(ctx); } evaluatedArgs.Add(add); } InvocationFrame invocationFrame = new InvocationFrame(); ctx.PushFrame(invocationFrame); TopicScope topicScope = new TopicScope(null, this); ctx.PushScope(topicScope); // make sure we can use local references IBELObject answer = block.Value(ctx, evaluatedArgs); ctx.PopScope(); ctx.PopFrame(); // make sure to transfer any new cache rules // BELTODO - want a test case for this foreach (CacheRule r in interpreter.CacheRules) ctx.AddCacheRule(r); return answer; }
public override IBELObject ValueOf(string name, System.Collections.ArrayList arguments, ExecutionContext ctx) { TopicPropertyCollection members = ctx.CurrentFederation.GetTopicProperties(Name); string val = members[name].LastValue; if (val == null) return null; val = val.Trim(); bool isBlock = val.StartsWith("{"); if (!isBlock) return new BELString(val); // It's a block, so fire up the interpreter if (!val.EndsWith("}")) throw new ExecutionException(ctx.CurrentLocation, "Topic member " + name + " defined in " + Name.DottedName + " is not well-formed; missing closing '}' for code block."); NamespaceManager cb = CurrentFederation.NamespaceManagerForTopic(Name); TopicContext newContext = new TopicContext(ctx.CurrentFederation, cb, CurrentTopicInfo); BehaviorInterpreter interpreter = new BehaviorInterpreter(Name.DottedName + "#" + name, val, CurrentFederation, CurrentFederation.WikiTalkVersion, ctx.Presenter); if (!interpreter.Parse()) throw new ExecutionException(ctx.CurrentLocation, "Syntax error in " + interpreter.ErrorString); IBELObject b1 = interpreter.EvaluateToObject(newContext, ctx.ExternalWikiMap); if (b1 == null) throw new ExecutionException(ctx.CurrentLocation, "Execution error in " + interpreter.ErrorString); Block block = (Block) b1; ArrayList evaluatedArgs = new ArrayList(); foreach (object each in arguments) { IBELObject add = null; if (each != null && each is IBELObject) add = each as IBELObject; else { ExposableParseTreeNode ptn = each as ExposableParseTreeNode; add = ptn.Expose(ctx); } evaluatedArgs.Add(add); } InvocationFrame invocationFrame = new InvocationFrame(); ctx.PushFrame(invocationFrame); TopicScope topicScope = new TopicScope(null, this); ctx.PushScope(topicScope); // make sure we can use local references IBELObject answer = block.Value(ctx, evaluatedArgs); ctx.PopScope(); ctx.PopFrame(); return answer; }
public IBELObject EvaluateToObject(TopicContext topicContext, Hashtable externalWikimap) { _CacheRules = new ArrayList(); if (ParseTree == null) { ErrorString = "Expression can not be evaluated; parse failed."; State = InterpreterState.EvaluationFailure; return null; } ExecutionContext ctx = new ExecutionContext(topicContext); ctx.WikiTalkVersion = WikiTalkVersion; IBELObject answer = null; try { ctx.ExternalWikiMap = externalWikimap; IScope theScope = null; ctx.Presenter = Presenter; TopicInfo topic = topicContext != null ? topicContext.CurrentTopic : null; if (topic != null && topic.Fullname != null) { // Locate any topics via the NamespaceWith property to see if there's anybody else we should import (for all topics in the namespace) ArrayList nswith = topicContext.CurrentFederation.GetTopicInfo(ctx, topicContext.CurrentTopic.ContentBase.DefinitionTopicName.Fullname).GetListProperty("NamespaceWith"); if (nswith != null) { nswith.Reverse(); foreach (string top in nswith) { AbsoluteTopicName abs = topic.ContentBase.UnambiguousTopicNameFor(new RelativeTopicName(top)); if (abs == null) { throw new Exception("No such topic: " + top + " (as specifed in NamespaceWith: property for " + topicContext.CurrentTopic.ContentBase.DefinitionTopicName.Fullname + ")"); } theScope = new TopicScope(theScope, new DynamicTopic(topic.Federation, abs)); ctx.AddCacheRule(new TopicsCacheRule(topic.Federation, abs)); } } // Locate any topics via the with property to see if there's anybody else we should import ArrayList with = topicContext.CurrentTopic.GetListProperty("With"); if (with != null) { with.Reverse(); foreach (string top in with) { AbsoluteTopicName abs = topic.ContentBase.UnambiguousTopicNameFor(new RelativeTopicName(top)); if (abs == null) { throw new Exception("No such topic: " + top + " (as specifed in With: property for " + topicContext.CurrentTopic + ")"); } theScope = new TopicScope(theScope, new DynamicTopic(topic.Federation, abs)); ctx.AddCacheRule(new TopicsCacheRule(topic.Federation, abs)); } } // add the topic to the current scope (this guy goes at the front of the queue!) theScope = new TopicScope(theScope, new DynamicTopic(topic.Federation, topic.Fullname)); } if (theScope != null) ctx.PushScope(theScope); // make sure we can use local references // parse tree -> live objects answer = ParseTree.Expose(ctx); if (theScope != null) ctx.PopScope(); _CacheRules = ctx.CacheRules; } catch (Exception e) { _CacheRules = ctx.CacheRules; ErrorString = e.Message; State = InterpreterState.EvaluationFailure; return null; } State = InterpreterState.EvaluationSuccess; return answer; }
public IBELObject Value(ExecutionContext ctx, ArrayList args) { if (ParseTree == null) return UndefinedObject.Instance; BlockScope blockScope = new BlockScope(ContainingScope); if (args != null) { if (args.Count != ParameterCount) throw new ArgumentException("Incorrect number of parameters for block. Need " + ParameterCount + "; got " + args.Count); // Determine desired types ArrayList neededTypes = new ArrayList(); foreach (BlockParameter parm in Parameters) { if (parm.TypeName == null) { neededTypes.Add(null); // they said it could be anything continue; } BELType t = (BELType)(ctx.TypeRegistry.Registry[parm.TypeName]); if (t == null) throw new ArgumentException("Block parameter (" + parm.Identifier + ") requires unknown type (" + parm.TypeName + ")"); neededTypes.Add(t); } // Check types, as requested ArrayList convertedArgs = new ArrayList(); for(int i = 0; i < ParameterCount; i++) { BlockParameter bp = (BlockParameter)(Parameters[i]); convertedArgs.Add(BELType.ConvertToBELObjectIfNeeded(args[i])); if (bp.TypeName == null) continue; // they said it could be anything IBELObject arg = (IBELObject)(convertedArgs[i]); Type parmType = ((BELType)(neededTypes[i])).CLRType; if (!parmType.IsAssignableFrom(arg.GetType())) throw new MemberInvocationException(ctx.CurrentLocation, "Block parameter " + bp.Identifier + " is not of the correct type (was " + ExternalTypeNameForType(arg.GetType()) + ", but needed " + ExternalTypeNameForType(parmType) + ")"); } // OK, we have them and they're type correct and converted to CLR types where needed. Add them into the block scope for(int i = 0; i < ParameterCount; i++) { BlockParameter bp = (BlockParameter)(Parameters[i]); blockScope.AddParameter(bp.Identifier, (IBELObject)(convertedArgs[i])); } } ctx.PushScope(blockScope); IBELObject answer = ParseTree.Expose(ctx); ctx.PopScope(); return answer; }
public IBELObject with(ExecutionContext ctx) { InvocationFrame frame = ctx.TopFrame; WithScope with = new WithScope(ctx.CurrentScope); if (frame.ExtraArguments.Count < 1) throw new ArgumentException("With requires at least a block to execute; zero arguments supplied."); int pushCount = frame.ExtraArguments.Count - 1; for (int i = pushCount - 1; i >= 0; i--) { ExposableParseTreeNode e = (ExposableParseTreeNode)frame.ExtraArguments[i]; IBELObject ex = e.Expose(ctx); with.AddObject(ex); } ctx.PushScope(with); // OK, now we have the new scope on the stack -- now it's safe to create the Block (since it'll "live in" the top scope ExposableParseTreeNode blockTree = (ExposableParseTreeNode)(frame.ExtraArguments[frame.ExtraArguments.Count - 1]); Block block = (blockTree.Expose(ctx)) as Block; if (block == null) throw new ArgumentException("With requires last argument to be a block; it isn't."); IBELObject answer = block.Value(ctx); ctx.PopScope(); return answer; }