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

net.sandius.rembulan.lib.impl.DefaultDebugLib Maven / Gradle / Ivy

/*
 * 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.lib.impl;

import net.sandius.rembulan.LuaRuntimeException;
import net.sandius.rembulan.Table;
import net.sandius.rembulan.Userdata;
import net.sandius.rembulan.Variable;
import net.sandius.rembulan.impl.UnimplementedFunction;
import net.sandius.rembulan.lib.BadArgumentException;
import net.sandius.rembulan.lib.DebugLib;
import net.sandius.rembulan.runtime.ExecutionContext;
import net.sandius.rembulan.runtime.LuaFunction;
import net.sandius.rembulan.runtime.ResolvedControlThrowable;
import net.sandius.rembulan.util.Check;

import java.lang.reflect.Field;

public class DefaultDebugLib extends DebugLib {

	private final LuaFunction _debug;
	private final LuaFunction _gethook;
	private final LuaFunction _getinfo;
	private final LuaFunction _getlocal;
	private final LuaFunction _getregistry;
	private final LuaFunction _sethook;
	private final LuaFunction _setlocal;
	private final LuaFunction _traceback;

	public DefaultDebugLib() {
		this._debug = new UnimplementedFunction("debug.debug");  // TODO
		this._gethook = new UnimplementedFunction("debug.gethook");  // TODO
		this._getinfo = new UnimplementedFunction("debug.getinfo");  // TODO
		this._getlocal = new UnimplementedFunction("debug.getlocal");  // TODO
		this._getregistry = new UnimplementedFunction("debug.getregistry");  // TODO
		this._sethook = new UnimplementedFunction("debug.sethook");  // TODO
		this._setlocal = new UnimplementedFunction("debug.setlocal");  // TODO
		this._traceback = new UnimplementedFunction("debug.traceback");  // TODO
	}

	@Override
	public LuaFunction _debug() {
		return _debug;
	}

	@Override
	public LuaFunction _gethook() {
		return _gethook;
	}

	@Override
	public LuaFunction _getinfo() {
		return _getinfo;
	}

	@Override
	public LuaFunction _getlocal() {
		return _getlocal;
	}

	@Override
	public LuaFunction _getmetatable() {
		return GetMetatable.INSTANCE;
	}

	@Override
	public LuaFunction _getregistry() {
		return _getregistry;
	}

	@Override
	public LuaFunction _getupvalue() {
		return GetUpvalue.INSTANCE;
	}

	@Override
	public LuaFunction _getuservalue() {
		return GetUserValue.INSTANCE;
	}

	@Override
	public LuaFunction _sethook() {
		return _sethook;
	}

	@Override
	public LuaFunction _setlocal() {
		return _setlocal;
	}

	@Override
	public LuaFunction _setmetatable() {
		return SetMetatable.INSTANCE;
	}

	@Override
	public LuaFunction _setupvalue() {
		return SetUpvalue.INSTANCE;
	}

	@Override
	public LuaFunction _setuservalue() {
		return SetUserValue.INSTANCE;
	}

	@Override
	public LuaFunction _traceback() {
		return _traceback;
	}

	@Override
	public LuaFunction _upvalueid() {
		return UpvalueId.INSTANCE;
	}

	@Override
	public LuaFunction _upvaluejoin() {
		return UpvalueJoin.INSTANCE;
	}


	private static class UpvalueRef {

		private final int index;
		private final LuaFunction function;
		private final Field field;

		public UpvalueRef(int index, LuaFunction function, Field field) {
			this.index = index;
			this.function = Check.notNull(function);
			this.field = Check.notNull(field);
		}

		// index is 0-based
		public static UpvalueRef find(LuaFunction f, int index) {
			Check.notNull(f);

			// find the index-th upvalue field
			int idx = 0;
			for (Field fld : f.getClass().getDeclaredFields()) {
				Class fldType = fld.getType();
				if (Variable.class.isAssignableFrom(fldType)) {
					if (idx == index) {
						// found it
						fld.setAccessible(true);
						return new UpvalueRef(index, f, fld);
					}
					else {
						idx += 1;
					}
				}
			}

			return null;
		}

		public String name() {
			return field.getName();
		}

		public int index() {
			return index;
		}

		public Variable get() throws IllegalAccessException {
			return (Variable) field.get(function);
		}

		public void set(Variable ref) throws IllegalAccessException {
			Check.notNull(ref);
			field.set(function, ref);
		}

	}

	public static class GetMetatable extends AbstractLibFunction {

		public static final GetMetatable INSTANCE = new GetMetatable();

		@Override
		protected String name() {
			return "getmetatable";
		}

		@Override
		protected void invoke(ExecutionContext context, ArgumentIterator args) throws ResolvedControlThrowable {
			Object value = args.nextAny();
			Table mt = context.getMetatable(value);
			context.getReturnBuffer().setTo(mt);
		}

	}

	public static class SetMetatable extends AbstractLibFunction {

		public static final SetMetatable INSTANCE = new SetMetatable();

		@Override
		protected String name() {
			return "setmetatable";
		}

		@Override
		protected void invoke(ExecutionContext context, ArgumentIterator args) throws ResolvedControlThrowable {
			Object value = args.peekOrNil();
			args.skip();
			Table mt = args.nextTableOrNil();

			// set the new metatable
			context.setMetatable(value, mt);

			// return value
			context.getReturnBuffer().setTo(value);
		}

	}

	public static class GetUpvalue extends AbstractLibFunction {

		public static final GetUpvalue INSTANCE = new GetUpvalue();

		@Override
		protected String name() {
			return "getupvalue";
		}

		@Override
		protected void invoke(ExecutionContext context, ArgumentIterator args) throws ResolvedControlThrowable {
			args.skip();
			int index = args.nextInt();
			args.rewind();
			LuaFunction f = args.nextFunction();

			UpvalueRef uvRef = UpvalueRef.find(f, index - 1);

			if (uvRef != null) {
				final String name;
				final Object value;

				try {
					name = uvRef.name();
					Variable uv = uvRef.get();
					value = uv.get();
				}
				catch (IllegalAccessException ex) {
					throw new LuaRuntimeException(ex);
				}

				context.getReturnBuffer().setTo(name, value);
			}
			else {
				// contrary to what its documentation says, PUC-Lua 5.3.2 doesn't seem to return
				// nil but rather an empty list
				context.getReturnBuffer().setTo();
			}

		}

	}

	public static class SetUpvalue extends AbstractLibFunction {

		public static final SetUpvalue INSTANCE = new SetUpvalue();

		@Override
		protected String name() {
			return "setupvalue";
		}

		@Override
		protected void invoke(ExecutionContext context, ArgumentIterator args) throws ResolvedControlThrowable {
			args.skip();
			args.skip();
			Object newValue = args.nextAny();
			args.rewind();
			args.skip();
			int index = args.nextInt();
			args.rewind();
			LuaFunction f = args.nextFunction();

			UpvalueRef uvRef = UpvalueRef.find(f, index - 1);

			final String name;

			if (uvRef != null) {
				try {
					name = uvRef.name();
					Variable uv = uvRef.get();
					uv.set(newValue);
				}
				catch (IllegalAccessException ex) {
					throw new LuaRuntimeException(ex);
				}
			}
			else {
				name = null;
			}

			context.getReturnBuffer().setTo(name);
		}

	}

	public static class UpvalueId extends AbstractLibFunction {

		public static final UpvalueId INSTANCE = new UpvalueId();

		@Override
		protected String name() {
			return "upvalueid";
		}

		@Override
		protected void invoke(ExecutionContext context, ArgumentIterator args) throws ResolvedControlThrowable {
			args.goTo(1);
			int n = args.nextInt();
			args.goTo(0);
			LuaFunction f = args.nextFunction();

			UpvalueRef uvRef = UpvalueRef.find(f, n - 1);
			if (uvRef == null) {
				throw new BadArgumentException(2, name(), "invalid upvalue index");
			}
			else {
				final Variable uv;
				try {
					uv = uvRef.get();
				}
				catch (IllegalAccessException ex) {
					throw new LuaRuntimeException(ex);
				}

				context.getReturnBuffer().setTo(uv);
			}
		}

	}

	public static class UpvalueJoin extends AbstractLibFunction {

		public static final UpvalueJoin INSTANCE = new UpvalueJoin();

		@Override
		protected String name() {
			return "upvaluejoin";
		}

		@Override
		protected void invoke(ExecutionContext context, ArgumentIterator args) throws ResolvedControlThrowable {
			// read f1, n1
			args.goTo(1);
			int n1 = args.nextInt();
			args.goTo(0);
			LuaFunction f1 = args.nextFunction();

			UpvalueRef uvRef1 = UpvalueRef.find(f1, n1 - 1);
			if (uvRef1 == null) {
				throw new BadArgumentException(2, name(), "invalid upvalue index");
			}

			// read f2, n2
			args.goTo(3);
			int n2 = args.nextInt();
			args.goTo(2);
			LuaFunction f2 = args.nextFunction();

			UpvalueRef uvRef2 = UpvalueRef.find(f2, n2 - 1);
			if (uvRef2 == null) {
				throw new BadArgumentException(4, name(), "invalid upvalue index");
			}

			try {
				uvRef1.set(uvRef2.get());
			}
			catch (IllegalAccessException ex) {
				throw new LuaRuntimeException(ex);
			}

			context.getReturnBuffer().setTo();
		}

	}

	public static class GetUserValue extends AbstractLibFunction {

		public static final GetUserValue INSTANCE = new GetUserValue();

		@Override
		protected String name() {
			return "getuservalue";
		}

		@Override
		protected void invoke(ExecutionContext context, ArgumentIterator args) throws ResolvedControlThrowable {
			Object o = args.peekOrNil();

			Object result = o instanceof Userdata ? ((Userdata) o).getUserValue() : null;
			context.getReturnBuffer().setTo(result);
		}

	}

	public static class SetUserValue extends AbstractLibFunction {

		public static final SetUserValue INSTANCE = new SetUserValue();

		@Override
		protected String name() {
			return "setuservalue";
		}

		@Override
		protected void invoke(ExecutionContext context, ArgumentIterator args) throws ResolvedControlThrowable {
			Userdata userdata = args.nextUserdata();
			Object value = args.nextAny();

			userdata.setUserValue(value);
			context.getReturnBuffer().setTo(userdata);
		}

	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy