diff --git a/src/Hassium/Compiler/CodeGen/Compiler.cs b/src/Hassium/Compiler/CodeGen/Compiler.cs index 8159ec4..add04ad 100644 --- a/src/Hassium/Compiler/CodeGen/Compiler.cs +++ b/src/Hassium/Compiler/CodeGen/Compiler.cs @@ -529,6 +529,17 @@ public void Accept(TernaryOperationNode node) node.FalseStatement.Visit(this); method.EmitLabel(node.SourceLocation, endLabel); } + public void Accept(ThreadNode node) + { + var temp = method; + method = new HassiumMethod(); + method.Name = "thread"; + node.Body.Visit(this); + if (!module.ObjectPool.ContainsKey(method.GetHashCode())) + module.ObjectPool.Add(method.GetHashCode(), method); + temp.Emit(node.SourceLocation, InstructionType.BuildThread, method.GetHashCode()); + method = temp; + } public void Accept(TraitNode node) { int hash = node.Name.GetHashCode(); diff --git a/src/Hassium/Compiler/CodeGen/InstructionType.cs b/src/Hassium/Compiler/CodeGen/InstructionType.cs index e8ffb41..921db9e 100644 --- a/src/Hassium/Compiler/CodeGen/InstructionType.cs +++ b/src/Hassium/Compiler/CodeGen/InstructionType.cs @@ -9,6 +9,7 @@ public enum InstructionType BuildDictionary, BuildKeyValuePair, BuildList, + BuildThread, BuildTuple, Call, Dereference, diff --git a/src/Hassium/Compiler/Parser/Ast/ThreadNode.cs b/src/Hassium/Compiler/Parser/Ast/ThreadNode.cs new file mode 100644 index 0000000..5048817 --- /dev/null +++ b/src/Hassium/Compiler/Parser/Ast/ThreadNode.cs @@ -0,0 +1,26 @@ +using System; + +namespace Hassium.Compiler.Parser.Ast +{ + public class ThreadNode: AstNode + { + public AstNode Body { get { return Children[0]; } } + + public ThreadNode(SourceLocation location, AstNode body) + { + this.SourceLocation = location; + Children.Add(body); + } + + public override void Visit(IVisitor visitor) + { + visitor.Accept(this); + } + public override void VisitChildren(IVisitor visitor) + { + foreach (AstNode child in Children) + child.Visit(visitor); + } + } +} + diff --git a/src/Hassium/Compiler/Parser/IVisitor.cs b/src/Hassium/Compiler/Parser/IVisitor.cs index 742e3ed..7762a3c 100644 --- a/src/Hassium/Compiler/Parser/IVisitor.cs +++ b/src/Hassium/Compiler/Parser/IVisitor.cs @@ -39,6 +39,7 @@ public interface IVisitor void Accept(StringNode node); void Accept(SwitchNode node); void Accept(TernaryOperationNode node); + void Accept(ThreadNode node); void Accept(TraitNode node); void Accept(TryCatchNode node); void Accept(TupleNode node); diff --git a/src/Hassium/Compiler/Parser/Parser.cs b/src/Hassium/Compiler/Parser/Parser.cs index a264ca6..55461d1 100644 --- a/src/Hassium/Compiler/Parser/Parser.cs +++ b/src/Hassium/Compiler/Parser/Parser.cs @@ -82,7 +82,7 @@ private AstNode parseStatement() block.Children.Add(parseStatement()); return block; } - else if (MatchToken(TokenType.Identifier) && Tokens[Position + 1].TokenType == TokenType.OpenBracket) + else if (MatchToken(TokenType.Identifier) && !MatchToken(TokenType.Identifier, "thread") && Tokens[Position + 1].TokenType == TokenType.OpenBracket) return parseProperty(); else if (MatchToken(TokenType.Identifier) && Tokens[Position + 1].TokenType == TokenType.Identifier) return parseEnforcedAssignment(); @@ -621,6 +621,8 @@ private AstNode parseTerm() return parseExpression(); else if (MatchToken(TokenType.Identifier, "lambda")) return parseLambda(); + else if (AcceptToken(TokenType.Identifier, "thread")) + return new ThreadNode(Location, parseStatement()); else if (MatchToken(TokenType.OpenSquare)) return parseListDeclaration(); else if (AcceptToken(TokenType.OpenBracket)) diff --git a/src/Hassium/Compiler/SemanticAnalysis/SemanticAnalyzer.cs b/src/Hassium/Compiler/SemanticAnalysis/SemanticAnalyzer.cs index 5946d45..f08366f 100644 --- a/src/Hassium/Compiler/SemanticAnalysis/SemanticAnalyzer.cs +++ b/src/Hassium/Compiler/SemanticAnalysis/SemanticAnalyzer.cs @@ -66,6 +66,7 @@ public void Accept(StatementNode node) {} public void Accept(StringNode node) {} public void Accept(SwitchNode node) {} public void Accept(TernaryOperationNode node) {} + public void Accept(ThreadNode node) {} public void Accept(TraitNode node) {} public void Accept(TryCatchNode node) {} public void Accept(TupleNode node) {} diff --git a/src/Hassium/Hassium.csproj b/src/Hassium/Hassium.csproj index 4ccf055..d484991 100644 --- a/src/Hassium/Hassium.csproj +++ b/src/Hassium/Hassium.csproj @@ -154,6 +154,9 @@ + + + diff --git a/src/Hassium/Runtime/Objects/HassiumMethod.cs b/src/Hassium/Runtime/Objects/HassiumMethod.cs index 1574df7..72f5cc2 100644 --- a/src/Hassium/Runtime/Objects/HassiumMethod.cs +++ b/src/Hassium/Runtime/Objects/HassiumMethod.cs @@ -48,46 +48,64 @@ public void EmitLabel(SourceLocation location, int label) // Instructions.Add(new Instruction(location, InstructionType.Label, label)); } + public HassiumObject Invoke(VirtualMachine vm, StackFrame.Frame frame) + { + vm.StackFrame.Frames.Push(frame); + return Invoke(vm); + } + public override HassiumObject Invoke(VirtualMachine vm, params HassiumObject[] args) { - if (Name != "lambda" && Name != "catch") vm.StackFrame.PushFrame(); - vm.CallStack.Push(SourceRepresentation); - int i = 0; - foreach (var param in Parameters) - { - var arg = args[i++]; - if (param.Key.IsEnforced) - if (!arg.Types.Contains((HassiumTypeDefinition)vm.Globals[param.Key.Type].Type())) - throw new InternalException(vm, InternalException.PARAMETER_ERROR, param.Key.Type, arg.Type()); - vm.StackFrame.Add(param.Value, arg); - } - if (IsConstructor) - { - HassiumClass ret = new HassiumClass(); - ret.Attributes = CloneDictionary(Parent.Attributes); - foreach (var type in Parent.Types) - ret.AddType(type); - foreach (var attrib in ret.Attributes.Values) - attrib.Parent = ret; - vm.ExecuteMethod(ret.Attributes["new"] as HassiumMethod); - vm.StackFrame.PopFrame(); - vm.CallStack.Pop(); - return ret; - } - else + try { - var val = vm.ExecuteMethod(this); - if (Name == "catch") + if (Name != "lambda" && Name != "catch" && Name != "thread") vm.StackFrame.PushFrame(); + vm.CallStack.Push(SourceRepresentation); + int i = 0; + foreach (var param in Parameters) { + var arg = args[i++]; + if (param.Key.IsEnforced) + if (!arg.Types.Contains((HassiumTypeDefinition)vm.Globals[param.Key.Type].Type())) + throw new InternalException(vm, InternalException.PARAMETER_ERROR, param.Key.Type, arg.Type()); + vm.StackFrame.Add(param.Value, arg); + } + if (IsConstructor) + { + HassiumClass ret = new HassiumClass(); + ret.Attributes = CloneDictionary(Parent.Attributes); + foreach (var type in Parent.Types) + ret.AddType(type); + foreach (var attrib in ret.Attributes.Values) + attrib.Parent = ret; + vm.ExecuteMethod(ret.Attributes["new"] as HassiumMethod); + vm.StackFrame.PopFrame(); + vm.CallStack.Pop(); + return ret; + } + else + { + var val = vm.ExecuteMethod(this); + if (Name == "catch") + { + vm.CallStack.Pop(); + return val; + } + if (ReturnType != "" && ReturnType != null) + if (val.Type() != vm.Globals[ReturnType]) + throw new InternalException(vm, InternalException.RETURN_ERROR, ReturnType, val.Type()); + if (Name != "lambda") vm.StackFrame.PopFrame(); vm.CallStack.Pop(); return val; } - if (ReturnType != "" && ReturnType != null) - if (val.Type() != vm.Globals[ReturnType]) - throw new InternalException(vm, InternalException.RETURN_ERROR, ReturnType, val.Type()); - if (Name != "lambda") vm.StackFrame.PopFrame(); - vm.CallStack.Pop(); - return val; + } + catch (InternalException ex) + { + Console.WriteLine("At location {0}:", ex.VM.CurrentSourceLocation); + Console.WriteLine("{0} at:", ex.Message); + while (ex.VM.CallStack.Count > 0) + Console.WriteLine(ex.VM.CallStack.Pop()); + Environment.Exit(0); + return null; } } diff --git a/src/Hassium/Runtime/Objects/Types/HassiumThread.cs b/src/Hassium/Runtime/Objects/Types/HassiumThread.cs new file mode 100644 index 0000000..3a73e4d --- /dev/null +++ b/src/Hassium/Runtime/Objects/Types/HassiumThread.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Threading; + +namespace Hassium.Runtime.Objects.Types +{ + public class HassiumThread: HassiumObject + { + public static new HassiumTypeDefinition TypeDefinition = new HassiumTypeDefinition("thread"); + + public Thread Thread { get; private set; } + + public HassiumThread(VirtualMachine vm, HassiumMethod method, StackFrame.Frame frame) + { + VirtualMachine newVM = vm.Clone() as VirtualMachine; + newVM.ExceptionReturns = new Dictionary(); + newVM.Handlers = new Stack(); + newVM.Stack = new Stack(); + newVM.StackFrame = new StackFrame(); + Thread = new Thread(() => method.Invoke(newVM, frame)); + + AddType(TypeDefinition); + AddAttribute("isAlive", new HassiumProperty(get_isAlive)); + AddAttribute("start", start, 0); + AddAttribute("stop", stop, 0); + } + + public HassiumBool get_isAlive(VirtualMachine vm, params HassiumObject[] args) + { + return new HassiumBool(Thread.IsAlive); + } + public HassiumNull start(VirtualMachine vm, params HassiumObject[] args) + { + Thread.Start(); + return HassiumObject.Null; + } + public HassiumNull stop(VirtualMachine vm, params HassiumObject[] args) + { + Thread.Abort(); + return HassiumObject.Null; + } + } +} \ No newline at end of file diff --git a/src/Hassium/Runtime/Objects/Types/HassiumTypesModule.cs b/src/Hassium/Runtime/Objects/Types/HassiumTypesModule.cs index 61e6fbe..3a1ffd9 100644 --- a/src/Hassium/Runtime/Objects/Types/HassiumTypesModule.cs +++ b/src/Hassium/Runtime/Objects/Types/HassiumTypesModule.cs @@ -17,10 +17,11 @@ public HassiumTypesModule() : base("types") AddAttribute("keyValuePair", HassiumKeyValuePair.TypeDefinition); AddAttribute("int", HassiumInt.TypeDefinition); AddAttribute("list", HassiumList.TypeDefinition); + AddAttribute("null", HassiumObject.Null); AddAttribute("object", HassiumObject.TypeDefinition); AddAttribute("property", HassiumProperty.TypeDefinition); - AddAttribute("null", HassiumObject.Null); AddAttribute("string", HassiumString.TypeDefinition); + AddAttribute("thread", HassiumThread.TypeDefinition); AddAttribute("trait", HassiumTrait.TypeDefinition); AddAttribute("TypeDefinition", HassiumTypeDefinition.TypeDefinition); } diff --git a/src/Hassium/Runtime/StackFrame.cs b/src/Hassium/Runtime/StackFrame.cs index 40bf865..acc0f3c 100644 --- a/src/Hassium/Runtime/StackFrame.cs +++ b/src/Hassium/Runtime/StackFrame.cs @@ -7,7 +7,7 @@ namespace Hassium.Runtime { public class StackFrame { - public class Frame + public class Frame : ICloneable { public Dictionary variables = new Dictionary(); public void Add(int index, HassiumObject value) @@ -26,6 +26,10 @@ public HassiumObject GetVariable(int index) { return variables[index]; } + public object Clone() + { + return this.MemberwiseClone(); + } } public Stack Frames; public Dictionary Locals { get { return Frames.Peek().variables; } } diff --git a/src/Hassium/Runtime/VirtualMachine.cs b/src/Hassium/Runtime/VirtualMachine.cs index 09113e0..8e1145e 100644 --- a/src/Hassium/Runtime/VirtualMachine.cs +++ b/src/Hassium/Runtime/VirtualMachine.cs @@ -10,17 +10,17 @@ namespace Hassium.Runtime { - public class VirtualMachine + public class VirtualMachine : ICloneable { public Stack CallStack { get; private set; } public HassiumMethod CurrentMethod { get; private set; } public HassiumModule CurrentModule { get; private set; } public SourceLocation CurrentSourceLocation { get; private set; } - public Dictionary ExceptionReturns { get; private set; } + public Dictionary ExceptionReturns { get; set; } public Dictionary Globals { get; private set; } - public Stack Handlers { get; private set; } - public Stack Stack { get; private set; } - public StackFrame StackFrame { get; private set; } + public Stack Handlers { get; set; } + public Stack Stack { get; set; } + public StackFrame StackFrame { get; set; } public void Execute(HassiumModule module, string[] args) { @@ -86,6 +86,9 @@ public HassiumObject ExecuteMethod(HassiumMethod method) elements[i] = Stack.Pop(); Stack.Push(new HassiumList(elements)); break; + case InstructionType.BuildThread: + Stack.Push(new HassiumThread(this, CurrentModule.ObjectPool[arg] as HassiumMethod, StackFrame.Frames.Peek())); + break; case InstructionType.BuildTuple: HassiumObject[] tupleElements = new HassiumObject[arg]; for (int i = 0; i < arg; i++) @@ -420,5 +423,10 @@ private void importInitials() foreach (var pair in CurrentModule.InitialVariables) CurrentModule.Globals.Add(pair.Key, pair.Value.Invoke(this)); } + + public object Clone() + { + return this.MemberwiseClone(); + } } } \ No newline at end of file diff --git a/src/Hassium/Runtime/VirtualMachineContext.cs b/src/Hassium/Runtime/VirtualMachineContext.cs new file mode 100644 index 0000000..71ce56d --- /dev/null +++ b/src/Hassium/Runtime/VirtualMachineContext.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; + +namespace Hassium.Runtime +{ + public class VirtualMachineContext + { + public VirtualMachineContext() + { + } + } +} +