Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions hscript/Ast.hx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ enum ExprDef {
EDoWhile(cond:Expr, body:Expr);
EMeta(name:String, args:Array<Expr>, expr:Expr);
EImport(path:String, mode:EImportMode);
EClass(name:VariableType, decl:ClassDecl);

EInfo(info:VariableInfo, expr:Expr);
EEmpty;
Expand Down Expand Up @@ -266,10 +267,31 @@ enum EImportMode {
All; // import haxe.*;
}

class ClassDecl {
public var name:String;
public var extend:Null<String>;
public var implement:Array<String>;
public var body:Expr; // Will be always EInfo along with a EBlock
public var isFinal:Bool;

public function new(name:String, ?extend:String, implement:Array<String>, body:Expr, isFinal:Bool) {
this.name = name;
this.extend = extend;
this.implement = implement;
this.body = body;
this.isFinal = isFinal;
}
}

typedef VariableType = Int;
typedef VariableInfo = Array<String>;

interface IHScriptCustomBehaviour {
public function hset(name:String, value:Dynamic):Dynamic;
public function hget(name:String):Dynamic;
}

//@:autoBuild(hscript.misc.classes.macro.HScriptClassMacro)
interface IHScriptClass extends IHScriptCustomBehaviour {
public var instance:hscript.types.classes.Instance;
}
75 changes: 57 additions & 18 deletions hscript/Interp.hx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package hscript;

import hscript.types.classes.ClassHandler;
import hscript.Ast.ClassDecl;
import haxe.ds.ObjectMap;
import haxe.ds.Map;
import haxe.ds.StringMap;
Expand Down Expand Up @@ -212,6 +214,20 @@ class ScriptRuntime {
return ref.r;
}

private inline function declarePublic(name:VariableType, value:Dynamic):Bool {
if(publicVariables == null) return false;
final varName:String = variableNames[name];
publicVariables.set(varName, value);
return true;
}

private inline function declareStatic(name:VariableType, value:Dynamic):Bool {
final varName:String = variableNames[name];
if(StaticInterp.staticVariables.exists(varName)) return false;
StaticInterp.staticVariables.set(varName, value);
return true;
}

private inline function assign(name:VariableType, value:Dynamic):Dynamic {
variablesDeclared[name] = true;
variablesValues[name].r = value;
Expand Down Expand Up @@ -322,15 +338,10 @@ class Interp extends ScriptRuntime {
case EIdent(name): if (variablesDeclared[name]) variablesValues[name].r; else resolveGlobal(name);
case EVar(name, init, isPublic, isStatic):
if (depth == 0) {
var varName:String = variableNames[name];
if (isStatic && !StaticInterp.staticVariables.exists(varName)) {
StaticInterp.staticVariables.set(varName, interpExpr(init));
if (isStatic && declareStatic(name, interpExpr(init)))
return null;
}
if (isPublic && publicVariables != null) {
publicVariables.set(varName, interpExpr(init));
if (isPublic && declarePublic(name, interpExpr(init)))
return null;
}
}
declare(name, init == null ? null : interpExpr(init));
return null;
Expand Down Expand Up @@ -446,6 +457,9 @@ class Interp extends ScriptRuntime {
var importValue:Dynamic = interpImport(path, mode);
if (importValue == null) error(EInvalidClass(path), expr.line);
return importValue;
case EClass(name, decl):
interpClass(name, decl);
return null;
case EInfo(info, _): error(ECustom("Invalid EInfo()"), expr.line);
case EEmpty: null;
}
Expand Down Expand Up @@ -485,6 +499,7 @@ class Interp extends ScriptRuntime {
return null;
}

// TODO: resolve custom class
private function interpImport(path:String, mode:EImportMode):Dynamic {
if (mode == All) return null; // not implemented

Expand All @@ -502,7 +517,7 @@ class Interp extends ScriptRuntime {
if (variablesDeclared[variableID]) return variablesValues[variableID].r;
}

var testClass:Either<Class<Dynamic>, Enum<Dynamic>> = StaticInterp.resolvePath(path);
var testClass:EitherOfThree<Class<Dynamic>, Dynamic, Enum<Dynamic>> = StaticInterp.resolvePath(path);
if (testClass == null) {
var splitPathCopy:Array<String> = splitPathName.copy();
splitPathCopy.splice(-2, 1);
Expand All @@ -514,6 +529,7 @@ class Interp extends ScriptRuntime {
if (testClass != null) {
var value:Dynamic = switch (testClass) {
case Left(resolvedClass): resolvedClass;
case Middle(resolvedValue): resolvedValue;
case Right(rawEnum): StaticInterp.resolveEnum(rawEnum);
}

Expand Down Expand Up @@ -600,13 +616,12 @@ class Interp extends ScriptRuntime {
functionRef.r = reflectiveFunction;
if (name != -1) {
if (depth == 0) {
var varName:String = variableNames[name];
if (isStatic && !StaticInterp.staticVariables.exists(varName)) {
StaticInterp.staticVariables.set(varName, reflectiveFunction);
if (isStatic) {
declareStatic(name, reflectiveFunction);
return reflectiveFunction;
}
if (isPublic && publicVariables != null) {
publicVariables.set(variableNames[name], reflectiveFunction);
if (isPublic) {
declarePublic(name, reflectiveFunction);
return reflectiveFunction;
}
}
Expand Down Expand Up @@ -749,9 +764,15 @@ class Interp extends ScriptRuntime {
if (classType == null) classType = resolveGlobal(className);

var params:Array<Dynamic> = [for (arg in args) interpExpr(arg)];
if(classType is ClassHandler)
return ClassHandler.createInstance(classType, params);
return Type.createInstance(classType, params);
}

private inline function interpClass(name:VariableType, decl:ClassDecl) {
declare(name, new ClassHandler(decl, this));
}

private function assignExpr(left:Expr, right:Expr):Dynamic {
var assignValue:Dynamic = interpExpr(right);
switch (left.expr) {
Expand Down Expand Up @@ -843,8 +864,21 @@ class Interp extends ScriptRuntime {
}
}

private enum EitherOfThree<L, M, R> {
Left(v:L);
Middle(v:M);
Right(v:R);
}

class StaticInterp {
public static var staticVariables:StringMap<Dynamic> = new StringMap<Dynamic>();
public static var staticVariables:StringMap<Dynamic> = new StringMap<Dynamic>();

/**
* Helper callback to return values that couldn't be resolved on import.
* @param String The attempted import classpath
* @return The defined value (or null of not found).
*/
public static var pathResolver:String -> Dynamic = null;

public static inline function evaluateBinop(op:ExprBinop, val1:Dynamic, val2:Dynamic):Dynamic {
switch (op) {
Expand Down Expand Up @@ -901,7 +935,7 @@ class StaticInterp {
}
}

// https://github.com/HaxeFoundation/hscript/blob/master/hscript/Interp.hx#L646-L652
// https://github.com/HaxeFoundation/hscript/blob/master/hscript/Interp.hx#L677-L683
public static inline function getMapValue(map:Dynamic, key:Dynamic):Dynamic {
return cast(map, IMap<Dynamic, Dynamic>).get(key);
}
Expand All @@ -910,13 +944,18 @@ class StaticInterp {
cast(map, IMap<Dynamic, Dynamic>).set(key, value);
}

public static function resolvePath(path:String):Either<Class<Dynamic>, Enum<Dynamic>> {
public static function resolvePath(path:String):EitherOfThree<Class<Dynamic>, Dynamic, Enum<Dynamic>> {
var resolvedClass:Class<Dynamic> = Type.resolveClass(path);
if (resolvedClass != null) return Left(resolvedClass);

var resolvedEnum:Enum<Dynamic> = Type.resolveEnum(path);
if (resolvedEnum != null) return Right(resolvedEnum);

if(pathResolver != null) {
var resolvedValue:Dynamic = pathResolver(path);
if(resolvedValue != null) return Middle(resolvedValue);
}

return null;
}

Expand Down Expand Up @@ -1065,7 +1104,7 @@ class InterpLocalsImpl {
return defaultsValues.get(key);
} else {
if (parent.variablesLookup != null && parent.variablesLookup.exists(key)) {
var varID:Int = parent.variablesLookup.get(key);
final varID:Int = parent.variablesLookup.get(key);
return parent.variablesDeclared[varID] ? parent.variablesValues[varID].r : null;
} else
return null;
Expand All @@ -1075,4 +1114,4 @@ class InterpLocalsImpl {
public inline function exists(key:String):Bool {
return parent.variablesLookup != null && parent.variablesLookup.exists(key) && parent.variablesDeclared[parent.variablesLookup.get(key)];
}
}
}
7 changes: 5 additions & 2 deletions hscript/Lexer.hx
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,12 @@ enum abstract LKeyword(String) from String {
var CASE:LKeyword = "case";
var CAST:LKeyword = "cast";
var CATCH:LKeyword = "catch";
var HCLASS:LKeyword = "class";
var CONTINUE:LKeyword = "continue";
var DEFAULT:LKeyword = "default";
var DO:LKeyword = "do";
var ELSE:LKeyword = "else";
var HEXTENDS:LKeyword = "extends";
var FALSE:LKeyword = "false";
var FINAL:LKeyword = "final";
var FOR:LKeyword = "for";
Expand All @@ -198,6 +200,7 @@ enum abstract LKeyword(String) from String {
var HIMPORT:LKeyword = "import"; // HIMPORT to prevent conflicts with lua libs
var IN:LKeyword = "in";
var HINLINE:LKeyword = "inline"; // HINLINE to prevent conflicts with lua libs
var HIMPLEMENTS:LKeyword = "implements";
var NEW:LKeyword = "new";
var NULL:LKeyword = "null";
var OVERRIDE:LKeyword = "override";
Expand All @@ -214,8 +217,8 @@ enum abstract LKeyword(String) from String {
var WHILE:LKeyword = "while";

public static final ALL_KEYWORDS:Array<LKeyword> = [
AS, BREAK, CASE, CAST, CATCH, CONTINUE, DEFAULT, DO, ELSE,
FALSE, FINAL, FOR, FUNCTION, IF, HIMPORT, IN, HINLINE,
AS, BREAK, CASE, CAST, CATCH, HCLASS, CONTINUE, DEFAULT, DO, ELSE, HEXTENDS,
FALSE, FINAL, FOR, FUNCTION, IF, HIMPORT, IN, HINLINE, HIMPLEMENTS,
NEW, NULL, OVERRIDE, PRIVATE, PUBLIC, RETURN, STATIC,
SWITCH, THIS, THROW, TRUE, TRY, VAR, WHILE
];
Expand Down
Loading