/* * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 * * Subject to the condition set forth below, permission is hereby granted to any * person obtaining a copy of this software, associated documentation and/or * data (collectively the "Software"), free of charge and under any and all * copyright rights in the Software, and any and all patent rights owned or * freely licensable by each licensor hereunder covering either (i) the * unmodified Software as contributed to or provided by such licensor, or (ii) * the Larger Works (as defined below), to deal in both * * (a) the Software, and * * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if * one is included with the Software each a "Larger Work" to which the Software * is contributed by such licensors), * * without restriction, including without limitation the rights to copy, create * derivative works of, display, perform, and distribute the Software and make, * use, sell, offer for sale, import, export, have made, and have sold the * Software and the Larger Work(s), and to sublicense the foregoing rights on * either these or other terms. * * This license is subject to the following condition: * * The above copyright notice and either this complete permission notice or at a * minimum a reference to the UPL must be included in all copies or substantial * portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package com.oracle.truffle.sl; import java.util.Map; import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.debug.DebuggerTags; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.instrumentation.ProvidedTags; import com.oracle.truffle.api.instrumentation.StandardTags; import com.oracle.truffle.api.metadata.ScopeProvider; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.sl.nodes.SLEvalRootNode; import com.oracle.truffle.sl.nodes.SLRootNode; import com.oracle.truffle.sl.nodes.local.SLLexicalScope; import com.oracle.truffle.sl.parser.Parser; import com.oracle.truffle.sl.runtime.SLBigNumber; import com.oracle.truffle.sl.runtime.SLContext; import com.oracle.truffle.sl.runtime.SLFunction; import com.oracle.truffle.sl.runtime.SLNull; @TruffleLanguage.Registration(name = "SL", version = "0.12", mimeType = SLLanguage.MIME_TYPE) @ProvidedTags({StandardTags.CallTag.class, StandardTags.StatementTag.class, StandardTags.RootTag.class, DebuggerTags.AlwaysHalt.class}) public final class SLLanguage extends TruffleLanguage<SLContext> implements ScopeProvider<SLContext> { public static volatile int counter; public static final String MIME_TYPE = "application/x-sl"; public SLLanguage() { counter++; } @Override protected SLContext createContext(Env env) { return new SLContext(this, env); } @Override protected CallTarget parse(ParsingRequest request) throws Exception { Source source = request.getSource(); Map<String, SLRootNode> functions; /* * Parse the provided source. At this point, we do not have a SLContext yet. Registration of * the functions with the SLContext happens lazily in SLEvalRootNode. */ if (request.getArgumentNames().isEmpty()) { functions = Parser.parseSL(this, source); } else { StringBuilder sb = new StringBuilder(); sb.append("function main("); String sep = ""; for (String argumentName : request.getArgumentNames()) { sb.append(sep); sb.append(argumentName); sep = ","; } sb.append(") { return "); sb.append(request.getSource().getCode()); sb.append(";}"); Source decoratedSource = Source.newBuilder(sb.toString()).mimeType(request.getSource().getMimeType()).name(request.getSource().getName()).build(); functions = Parser.parseSL(this, decoratedSource); } SLRootNode main = functions.get("main"); SLRootNode evalMain; if (main != null) { /* * We have a main function, so "evaluating" the parsed source means invoking that main * function. However, we need to lazily register functions into the SLContext first, so * we cannot use the original SLRootNode for the main function. Instead, we create a new * SLEvalRootNode that does everything we need. */ evalMain = new SLEvalRootNode(this, main.getFrameDescriptor(), main.getBodyNode(), main.getSourceSection(), main.getName(), functions); } else { /* * Even without a main function, "evaluating" the parsed source needs to register the * functions into the SLContext. */ evalMain = new SLEvalRootNode(this, null, null, null, "[no_main]", functions); } return Truffle.getRuntime().createCallTarget(evalMain); } @Override protected Object findExportedSymbol(SLContext context, String globalName, boolean onlyExplicit) { return context.getFunctionRegistry().lookup(globalName, false); } @Override protected Object getLanguageGlobal(SLContext context) { /* * The context itself is the global function registry. SL does not have global variables. */ return context; } @Override protected boolean isVisible(SLContext context, Object value) { return value != SLNull.SINGLETON; } @Override protected boolean isObjectOfLanguage(Object object) { return object instanceof SLFunction; } @Override protected String toString(SLContext context, Object value) { if (value == SLNull.SINGLETON) { return "NULL"; } if (value instanceof SLBigNumber) { return super.toString(context, ((SLBigNumber) value).getValue()); } if (value instanceof Long) { return Long.toString((Long) value); } return super.toString(context, value); } @Override protected Object findMetaObject(SLContext context, Object value) { if (value instanceof Number || value instanceof SLBigNumber) { return "Number"; } if (value instanceof Boolean) { return "Boolean"; } if (value instanceof String) { return "String"; } if (value == SLNull.SINGLETON) { return "Null"; } if (value instanceof SLFunction) { return "Function"; } return "Object"; } @Override protected SourceSection findSourceLocation(SLContext context, Object value) { if (value instanceof SLFunction) { SLFunction f = (SLFunction) value; return f.getCallTarget().getRootNode().getSourceSection(); } return null; } @Override public AbstractScope findScope(SLContext context, Node node, Frame frame) { return SLLexicalScope.createScope(node); } }