content: /*******************************************************************************
  * Copyright (c) 2009-2011 Luaj.org. All rights reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  * copies of the Software, and to permit persons to whom the Software is
  * furnished to do so, subject to the following conditions:
  *
  * The above copyright notice and this permission notice shall 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 org.luaj.vm2.compiler;
  
  import java.io.IOException;
  import java.io.InputStream;
  import java.util.Hashtable;
  
  import org.luaj.vm2.Globals;
  import org.luaj.vm2.LocVars;
  import org.luaj.vm2.Lua;
  import org.luaj.vm2.LuaClosure;
  import org.luaj.vm2.LuaError;
  import org.luaj.vm2.LuaFunction;
  import org.luaj.vm2.LuaString;
  import org.luaj.vm2.LuaValue;
  import org.luaj.vm2.Prototype;
  import org.luaj.vm2.Upvaldesc;
  import org.luaj.vm2.lib.BaseLib;
  
  /**
   * Compiler for Lua.
   * 
   * <p>
   * Compiles lua source files into lua bytecode within a {@link Prototype}, 
   * loads lua binary files directly into a{@link Prototype}, 
   * and optionaly instantiates a {@link LuaClosure} around the result 
   * using a user-supplied environment.  
   * 
   * <p>
   * Implements the {@link Globals.Compiler} interface for loading 
   * initialized chunks, which is an interface common to 
   * lua bytecode compiling and java bytecode compiling.
   *  
   * <p> 
   * The {@link LuaC} compiler is installed by default by both the 
   * {@link JsePlatform} and {@link JmePlatform} classes, 
   * so in the following example, the default {@link LuaC} compiler 
   * will be used:
   * <pre> {@code
   * Globals globals = JsePlatform.standardGlobals();
   * globals.load(new StringReader("print 'hello'"), "main.lua" ).call();
   * } </pre>
   * 
   * To load the LuaC compiler manually, use the install method:
   * <pre> {@code
   * LuaC.install(globals);
   * } </pre>
   * 
   * @see LuaC#install(Globals)
   * @see Globals#Compiler
   * @see Globals#Loader
   * @see LuaJC
   * @see JsePlatform
   * @see JmePlatform
   * @see BaseLib
   * @see LuaValue
   * @see LuaCompiler
   * @see Prototype
   */
  public class LuaC extends Lua implements Globals.Compiler, Globals.Loader {
  
  	/** A sharable instance of the LuaC compiler. */
  	public static final LuaC instance = new LuaC();
  	
  	/** Install the compiler so that LoadState will first 
  	 * try to use it when handed bytes that are 
  	 * not already a compiled lua chunk.
  	 * @param globals the Globals into which this is to be installed.
  	 */
  	public static void install(Globals globals) {
  		globals.compiler = instance;
  		globals.loader = instance;
  	}
  
  	protected static void _assert(boolean b) {		
  		if (!b)
  			throw new LuaError("compiler assert failed");
  	}
  	
  	public static final int MAXSTACK = 250;
  	static final int LUAI_MAXUPVAL = 0xff;
  	static final int LUAI_MAXVARS = 200;
  	static final int NO_REG		 = MAXARG_A;
  	
  
  	/* OpMode - basic instruction format */
  	static final int 
  		iABC = 0,
  		iABx = 1,
  		iAsBx = 2;
  
  	/* OpArgMask */
  	static final int 
  	  OpArgN = 0,  /* argument is not used */
  	  OpArgU = 1,  /* argument is used */
  	  OpArgR = 2,  /* argument is a register or a jump offset */
  	  OpArgK = 3;   /* argument is a constant or register/constant */
  
  
  	static void SET_OPCODE(InstructionPtr i,int o) {
  		i.set( ( i.get() & (MASK_NOT_OP)) | ((o << POS_OP) & MASK_OP) );
  	}
  	
  	static void SETARG_A(int[] code, int index, int u) {
  		code[index] = (code[index] & (MASK_NOT_A)) | ((u << POS_A) & MASK_A);
  	}
  
  	static void SETARG_A(InstructionPtr i,int u) {
  		i.set( ( i.get() & (MASK_NOT_A)) | ((u << POS_A) & MASK_A) );
  	}
  
  	static void SETARG_B(InstructionPtr i,int u) {
  		i.set( ( i.get() & (MASK_NOT_B)) | ((u << POS_B) & MASK_B) );
  	}
  
  	static void SETARG_C(InstructionPtr i,int u) {
  		i.set( ( i.get() & (MASK_NOT_C)) | ((u << POS_C) & MASK_C) );
  	}
  	
  	static void SETARG_Bx(InstructionPtr i,int u) {
  		i.set( ( i.get() & (MASK_NOT_Bx)) | ((u << POS_Bx) & MASK_Bx) );
  	}
  	
  	static void SETARG_sBx(InstructionPtr i,int u) {
  		SETARG_Bx( i, u + MAXARG_sBx );
  	}
  
  	static int CREATE_ABC(int o, int a, int b, int c) {
  		return ((o << POS_OP) & MASK_OP) |
  				((a << POS_A) & MASK_A) |
  				((b << POS_B) & MASK_B) |
  				((c << POS_C) & MASK_C) ;
  	}
  	
  	static int CREATE_ABx(int o, int a, int bc) {
  		return ((o << POS_OP) & MASK_OP) |
  				((a << POS_A) & MASK_A) |
  				((bc << POS_Bx) & MASK_Bx) ;
   	}
  
  	// vector reallocation
  	
  	static LuaValue[] realloc(LuaValue[] v, int n) {
  		LuaValue[] a = new LuaValue[n];
  		if ( v != null )
  			System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
  		return a;
  	}
  
  	static Prototype[] realloc(Prototype[] v, int n) {
  		Prototype[] a = new Prototype[n];
  		if ( v != null )
  			System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
  		return a;
  	}
  
  	static LuaString[] realloc(LuaString[] v, int n) {
  		LuaString[] a = new LuaString[n];
  		if ( v != null )
  			System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
  		return a;
  	}
  
  	static LocVars[] realloc(LocVars[] v, int n) {
  		LocVars[] a = new LocVars[n];
  		if ( v != null )
  			System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
  		return a;
  	}
  
  	static Upvaldesc[] realloc(Upvaldesc[] v, int n) {
  		Upvaldesc[] a = new Upvaldesc[n];
  		if ( v != null )
  			System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
  		return a;
  	}
  
  	static LexState.Vardesc[] realloc(LexState.Vardesc[] v, int n) {
  		LexState.Vardesc[] a = new LexState.Vardesc[n];
  		if ( v != null )
  			System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
  		return a;
  	}
  
  	static LexState.Labeldesc[] grow(LexState.Labeldesc[] v, int min_n) {
  		return v == null ? new LexState.Labeldesc[2] : v.length < min_n ? realloc(v, v.length*2) : v; 
  	}
  	
  	static LexState.Labeldesc[] realloc(LexState.Labeldesc[] v, int n) {
  		LexState.Labeldesc[] a = new LexState.Labeldesc[n];
  		if ( v != null )
  			System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
  		return a;
  	}
  
  	static int[] realloc(int[] v, int n) {
  		int[] a = new int[n];
  		if ( v != null )
  			System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
  		return a;
  	}
  
  	static byte[] realloc(byte[] v, int n) {
  		byte[] a = new byte[n];
  		if ( v != null )
  			System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
  		return a;
  	}
  
  	static char[] realloc(char[] v, int n) {
  		char[] a = new char[n];
  		if ( v != null )
  			System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
  		return a;
  	}
  
  	public int nCcalls;
  	Hashtable strings;
  
  	protected LuaC() {}
  	
  	private LuaC(Hashtable strings) {
  		 this.strings = strings;
  	}
  
  	/** Compile lua source into a Prototype.
  	 * @param stream InputStream representing the text source conforming to lua source syntax.
  	 * @param chunkname String name of the chunk to use.
  	 * @return Prototype representing the lua chunk for this source.
  	 * @throws IOException
  	 */
  	public Prototype compile(InputStream stream, String chunkname, boolean standardSyntax) throws IOException {
  		return (new LuaC(new Hashtable())).luaY_parser(stream, chunkname, standardSyntax);
  	}
  
  	/** @deprecated
  	 * Use Globals.load(InputString, String, String) instead, 
  	 * or LuaC.compil(InputStream, String) and construct LuaClosure directly.
  	 */
  	public LuaValue load(InputStream stream, String chunkname, Globals globals) throws IOException {
  		return new LuaClosure(compile(stream, chunkname, globals.isStandardSyntax()), globals);
  	}
  
  
  	/** Parse the input */
  	private Prototype luaY_parser(InputStream z, String name, boolean standardSyntax) throws IOException{
  		LexState lexstate = new LexState(this, z, standardSyntax);
  		FuncState funcstate = new FuncState();
  		// lexstate.buff = buff;
  		lexstate.fs = funcstate;
  		lexstate.setinput( this, z.read(), z, (LuaString) LuaValue.valueOf(name) );
  		/* main func. is always vararg */
  		funcstate.f = new Prototype();
  		funcstate.f.source = (LuaString) LuaValue.valueOf(name);
  		lexstate.mainfunc(funcstate);
  		LuaC._assert (funcstate.prev == null);
  		/* all scopes should be correctly finished */
  		LuaC._assert (lexstate.dyd == null 
  				|| (lexstate.dyd.n_actvar == 0 && lexstate.dyd.n_gt == 0 && lexstate.dyd.n_label == 0));
  		return funcstate.f;
  	}
  
  	// look up and keep at most one copy of each string
  	public LuaString newTString(String s) {
  		return cachedLuaString(LuaString.valueOf(s));
  	}
  
  	// look up and keep at most one copy of each string
  	public LuaString newTString(LuaString s) {
  		return cachedLuaString(s);
  	}
  
  	public LuaString cachedLuaString(LuaString s) {
  		LuaString c = (LuaString) strings.get(s);
  		if (c != null) 
  			return c;
  		strings.put(s, s);
  		return s;
  	}
  
  	public String pushfstring(String string) {
  		return string;
  	}
  
  	public LuaFunction load(Prototype prototype, String chunkname, LuaValue env) throws IOException {
  		return new LuaClosure(prototype, env);
  	}
  }
  