Example #1
0
        private Expression BuildIdentifierRootExpression(ParseTreeNode root, CompilerState state)
        {
            AtomMetadata atom;
            var          name = root.ChildNodes[0].Token.ValueString;

            // first, look for an argument with this name
            var argument = state.TryGetArgumentByName(name);

            if (argument != null)
            {
                return(argument);
            }

            var context = state.Context;

            // next, see if we have a field or property on the context (if any context present)
            var contextBoundExpression = TryGetFieldOrPropertyInfoFromContext(name, context);

            if (contextBoundExpression != null)
            {
                return(contextBoundExpression);
            }

            // and only then look through available IDENTIFIER atoms
            if (m_atoms.TryGetValue(name, out atom) && atom.AtomType == AtomType.Identifier)
            {
                if (atom.ExpressionGenerator != null)
                {
                    return(atom.ExpressionGenerator(root, state));
                }

                if (atom.MethodInfo == null)
                {
                    // internal error, somebody screwed up with configuration of runtime
                    throw new Exception("ExpressionGenerator and MethodInfo are both null on atom: " + atom.Name);
                }

                // no arguments? great
                var paramInfo = atom.MethodInfo.GetParameters();
                if (paramInfo.Length == 0)
                {
                    return(BuildFunctorInvokeExpression(atom, (Expression[])null));
                }

                // any arguments? must have exactly one argument, context must be registered, and context type must be adjustable to this method's arg type
                if (context == null)
                {
                    throw new CompilationException("Atom's MethodInfo cannot be used for an Id expression, because context is not available: " + atom.Name, root);
                }

                Expression adjustedContext;
                if (paramInfo.Length > 1 || !ExpressionTreeExtensions.TryAdjustReturnType(root, context, paramInfo[0].ParameterType, out adjustedContext))
                {
                    throw new CompilationException("Atom's MethodInfo may only have either zero arguments or one argument of the same type as expression context: " + atom.Name, root);
                }

                return(BuildFunctorInvokeExpression(atom, adjustedContext));
            }

            // still nothing found? ask IDENTIFIER atom handlers
            foreach (var handler in m_atomHandlers)
            {
                if (handler.AtomType != AtomType.Identifier)
                {
                    continue;
                }

                if (handler.ExpressionGenerator == null)
                {
                    // internal error, somebody screwed up with configuration of runtime
                    throw new Exception("ExpressionGenerator is null on atom handler: " + handler.Name);
                }

                // only pass the first portion of dot-notation identifier to handler
                var result = handler.ExpressionGenerator(root.ChildNodes[0], state);
                if (result != null)
                {
                    return(result);
                }
            }

            throw new CompilationException("Unknown atom: " + name, root);
        }