All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sandius.rembulan.parser.analysis.NameResolutionTransformer Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2016 Miroslav Janíček
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.sandius.rembulan.parser.analysis;

import net.sandius.rembulan.parser.ast.*;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

class NameResolutionTransformer extends Transformer {

	private FunctionVarInfoBuilder fnScope;

	public NameResolutionTransformer(FunctionVarInfoBuilder fnScope) {
		this.fnScope = fnScope;
	}

	public NameResolutionTransformer() {
		this(null);
	}

	protected void enterFunction() {
		fnScope = new FunctionVarInfoBuilder(fnScope);
	}

	protected FunctionVarInfo leaveFunction() {
		FunctionVarInfoBuilder scope = fnScope;
		fnScope = scope.parent();
		return scope.toVarInfo();
	}

	@Override
	public Chunk transform(Chunk chunk) {
		enterFunction();
		Chunk c = chunk.update(transform(chunk.block()));
		FunctionVarInfo varInfo = leaveFunction();
		return c.with(varInfo);
	}

	@Override
	public Block transform(Block block) {
		fnScope.enterBlock();
		Block b = super.transform(block);
		fnScope.leaveBlock();
		return b;
	}

	@Override
	public BodyStatement transform(LocalDeclStatement node) {
		List resolvedInitialisers = transformExprList(node.initialisers());

		List ns = transformNameList(node.names());
		List vs = new ArrayList<>();
		for (Name n : ns) {
			Variable v = fnScope.addLocal(n);
			vs.add(v);
		}
		return node
				.update(ns, resolvedInitialisers)
				.with(new VarMapping(Collections.unmodifiableList(vs)));
	}

	@Override
	public BodyStatement transform(NumericForStatement node) {
		Name n = transform(node.name());

		Expr init = node.init().accept(this);
		Expr limit = node.limit().accept(this);
		Expr step = node.step() != null ? node.step().accept(this) : null;

		fnScope.enterBlock();
		Variable v = fnScope.addLocal(n);
		node = node.update(n, init, limit, step, transform(node.block()));
		node = node.with(new VarMapping(v));
		fnScope.leaveBlock();

		return node;
	}

	@Override
	public BodyStatement transform(GenericForStatement node) {
		List ns = transformNameList(node.names());
		List es = transformExprList(node.exprs());

		List vs = new ArrayList<>();

		fnScope.enterBlock();
		for (Name n : ns) {
			Variable v = fnScope.addLocal(n);
			vs.add(v);
		}
		node = node.update(ns, es, transform(node.block()));
		node = node.with(new VarMapping(Collections.unmodifiableList(vs)));
		fnScope.leaveBlock();

		return node;
	}

	@Override
	public BodyStatement transform(RepeatUntilStatement node) {
		fnScope.enterBlock();
		Block b = super.transform(node.block());
		Expr c = node.condition().accept(this);
		node = node.update(c, b);
		fnScope.leaveBlock();

		return node;
	}


	@Override
	public FunctionDefExpr transform(FunctionDefExpr e) {
		enterFunction();

		fnScope.enterBlock();
		FunctionDefExpr.Params ps = transform(e.params());
		for (Name n : ps.names()) {
			fnScope.addParam(n);
		}

		e = e.update(ps, transform(e.block()));
		fnScope.leaveBlock();

		FunctionVarInfo varInfo = leaveFunction();
		e = e.with(varInfo);

		if (!ps.isVararg() && varInfo.isVararg()) {
			throw new IllegalStateException("cannot use '...' outside a vararg function");
		}

		return e;
	}

	@Override
	public LValueExpr transform(VarExpr e) {
		if (e.attributes().has(ResolvedVariable.class)) {
			throw new IllegalStateException("variable already resolved: " + e.name() + " -> " + e.attributes().get(ResolvedVariable.class));
		}

		ResolvedVariable bound = fnScope.resolve(e.name());
		if (bound != null) {
			return e.with(bound);
		}
		else {
			// not resolved: translate to _ENV[name]
			ResolvedVariable env = fnScope.resolve(Variable.ENV_NAME);

			assert (env != null);

			Attributes attr = e.attributes();
			return new IndexExpr(attr,
					new VarExpr(attr.with(env), Variable.ENV_NAME),
					new LiteralExpr(attr, StringLiteral.fromName(e.name())));
		}
	}

	@Override
	public Expr transform(VarargsExpr e) {
		fnScope.setVararg();
		return super.transform(e);
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy