diff --git a/examples/test.gs b/examples/test.gs
index 7c0d49b..fa68652 100644
--- a/examples/test.gs
+++ b/examples/test.gs
@@ -1,3 +1,2 @@
-point(3 | 4)
-
-point(6 | 7)
\ No newline at end of file
+[point(3, 4) -> A]
+line(A, point(7, 8))
\ No newline at end of file
diff --git a/src/doc/syntax.md b/src/doc/syntax.md
index 14005e0..173f3ac 100644
--- a/src/doc/syntax.md
+++ b/src/doc/syntax.md
@@ -1,16 +1,31 @@
# Syntax
```
-point(3 | 4) -> A
-point(6 | 7) -> B
+[point(3, 4) -> A]
+point(6, 7) -> B
-line(A, B) -> AB
-line(0 | 0, 100 | 100)
+line[color=red, weight=4](A, B) -> AB
+line(point(0, 0), point(100, 100))
circle(A, len(AB))
```
-## Primitives
-* `Point point(x, y)` is a 2D point. It returns an element of type `Point`
-* `Line line(Point from, Point to)` is a straight line. It returns an element of type `Line`.
-* `Circle circle(Point center, radius)` draws a circle at `center` and `radius`
\ No newline at end of file
+## Behaviour
+Every line is one instruction. It is possible to assign instructions names to re-use them later.
+These variables are immutable. Objects do not exist in this script, in fact, variables are more similar to C-style macros than actual variables.
+
+Lines in brackets `[]` are "hidden". They are parsed, but will not be rendered.
+
+It is possible to add an optional set of parameters in front of each parameter list, in order to specify the appearance of the element.
+
+## Primitives vs Functions
+Primitives (e.g. `point`, `line`) and Functions (e.g. `len`, `intersection`) are syntactically indistinguishable.
+Both can be used as parameters or instructions and can be assigned to variables. The only difference is that Primitives generate a visual output (unless they are surrounded by square brackets)
+
+## Grammar
+```
+instruction ::= identifier({parameter, }) [-> identifer]
+parameter ::= instruction | identifier | number
+identifier ::= (A-Za-z)
+number ::= (0-9)[.(0-9)]
+```
diff --git a/src/geometry.ts b/src/geometry.ts
index 58abec9..64da89e 100644
--- a/src/geometry.ts
+++ b/src/geometry.ts
@@ -1,10 +1,11 @@
-import { Vector2D } from "./vector.js"
-import * as shape from "./shapes.js"
+///
+///
+///
function loadScript(filepath: string): string
{
- var result = null;
- var xmlhttp = new XMLHttpRequest();
+ let result = null;
+ let xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", filepath, false);
xmlhttp.send();
if (xmlhttp.status==200) {
@@ -23,7 +24,7 @@ class Geometry extends HTMLElement
constructor()
{
super();
-
+ console.log("constructor")
if(!this.hasAttribute("src"))
{
return;
@@ -32,32 +33,10 @@ class Geometry extends HTMLElement
let sourceFile = this.getAttribute("src");
let content = loadScript(sourceFile);
- let lines = content.split("\n");
- for(let line of lines)
+ let parser = new Parser(content);
+ for(let instr of parser.instructions)
{
- if(line === "\r")
- {
- console.log("empty");
- continue;
- }
-
- let instruction = line.split("(")[0];
-
- switch(instruction)
- {
- case instruction:
- {
- let coords = line.split("(")[1].split("|");
- console.log(coords);
- break;
- }
-
- default:
- {
- console.log("something else");
- break;
- }
- }
+ console.log(instr.eval());
}
this.attachShadow({mode: "open"});
@@ -76,8 +55,8 @@ class Geometry extends HTMLElement
private redraw()
{
- shape.line(this.context, new Vector2D(), new Vector2D(300, 300));
- shape.circle(this.context, new Vector2D(150, 150), 100);
+ line(this.context, new Vector2D(), new Vector2D(300, 300));
+ circle(this.context, new Vector2D(150, 150), 100);
}
}
diff --git a/src/parser/instruction.ts b/src/parser/instruction.ts
new file mode 100644
index 0000000..67f49c6
--- /dev/null
+++ b/src/parser/instruction.ts
@@ -0,0 +1,51 @@
+///
+
+enum InstructionType
+{
+ Point,
+ Line,
+ Circle
+}
+
+abstract class Instruction
+{
+ public fn: InstructionType;
+ public params :Parameter[];
+
+ constructor(type: InstructionType)
+ {
+ this.fn = type;
+ this.params = [];
+ }
+
+ abstract eval();
+}
+
+class PointInstruction extends Instruction
+{
+ constructor()
+ {
+ super(InstructionType.Point);
+ }
+
+ eval()
+ {
+ return new Vector2D(this.params[0].eval(), this.params[1].eval());
+ }
+}
+
+class LineInstruction extends Instruction
+{
+ constructor()
+ {
+ super(InstructionType.Line);
+ }
+
+ eval()
+ {
+ return [
+ this.params[0].eval(),
+ this.params[1].eval()
+ ];
+ }
+}
\ No newline at end of file
diff --git a/src/parser/parameter.ts b/src/parser/parameter.ts
new file mode 100644
index 0000000..efce571
--- /dev/null
+++ b/src/parser/parameter.ts
@@ -0,0 +1,52 @@
+enum ParameterType
+{
+ Instruction,
+ Identifier,
+ Number
+}
+
+abstract class Parameter
+{
+ public type: ParameterType;
+
+ constructor(type: ParameterType)
+ {
+ this.type = type;
+ }
+
+ abstract eval();
+}
+
+class NumberParameter extends Parameter
+{
+ public val: number;
+
+ constructor(val: number)
+ {
+ super(ParameterType.Number);
+
+ this.val = val;
+ }
+
+ eval()
+ {
+ return this.val;
+ }
+}
+
+class InstructionParameter extends Parameter
+{
+ public instr: Instruction;
+
+ constructor(instr: Instruction)
+ {
+ super(ParameterType.Identifier);
+
+ this.instr = instr;
+ }
+
+ eval()
+ {
+ return this.instr.eval();
+ }
+}
\ No newline at end of file
diff --git a/src/parser/parser.ts b/src/parser/parser.ts
new file mode 100644
index 0000000..2a74445
--- /dev/null
+++ b/src/parser/parser.ts
@@ -0,0 +1,153 @@
+///
+///
+
+class Parser
+{
+ public instructions: Instruction[];
+ private variables: { [id: string] : InstructionParameter};
+
+ constructor(source: string)
+ {
+ this.instructions = [];
+ this.variables = {};
+
+ let lines = source.split(/\r?\n/);
+ for(let line of lines)
+ {
+ let instr = this.parseInstruction(line);
+ if(!instr[0])
+ this.instructions.push(instr[1]);
+ }
+ }
+
+ private parseInstruction(instruction: string): [boolean, Instruction]
+ {
+ // If the instruction is an empty line, do nothing for now
+ if(instruction === "")
+ return null;
+
+ let hidden = false;
+ if(instruction[0] === "[" && instruction[instruction.length - 1] === "]")
+ {
+ hidden = true;
+ instruction = instruction.substring(1, instruction.length - 1);
+ }
+
+ instruction = instruction.split(" ").join(""); // Remove spaces
+
+ // match the pattern "text(text)"
+ let matches = instruction.match(/[A-Za-z]*\(.*\)/);
+ if(matches === null) // no match found
+ {
+ console.error("Invalid syntax");
+ return null;
+ }
+
+ if(matches.length > 1) // more than one match
+ {
+ console.error("Script may only contain one instruction per line");
+ return null;
+ }
+
+ let instr = matches[0]; // get the instruction
+ let paranthesisPos = instr.search(/\(/); // Find the position of the first opening paranthesis
+
+
+ let symbol = instr.substr(0, paranthesisPos); // get function name
+ let paramlist = instr.substring(paranthesisPos + 1, instr.length - 1); // get parameter list
+
+ let match;
+ let params = [];
+ while((match = paramlist.search(/,(?![^\(]*\))/)) !== -1)
+ {
+ params.push(paramlist.substring(0, match));
+ paramlist = paramlist.substring(match + 1, paramlist.length);
+ }
+ params.push(paramlist);
+
+ let newInstruction;
+ switch(symbol)
+ {
+ case "point":
+ {
+ newInstruction = new PointInstruction();
+ break;
+ }
+
+ case "line":
+ {
+ newInstruction = new LineInstruction();
+ break;
+ }
+
+ default:
+ {
+ console.error("Unknown instruction \"" + symbol + "\"");
+ return null;
+ }
+ }
+
+ for(let param of params)
+ {
+ if(!this.parseParameter(newInstruction, param))
+ {
+ console.error("Error during parameter parsing: \"" + param + "\" failed to be parsed.");
+ return null;
+ }
+ }
+
+ let assignment = instruction.search(/->/);
+ if(assignment !== -1)
+ {
+ let variableName = instruction.substring(assignment + 2, instruction.length);
+
+ if(variableName in this.variables)
+ {
+ console.error("Redefinition of variable \"" + variableName + "\" is not allowed.");
+ return null;
+ }
+
+ this.variables[variableName] = new InstructionParameter(newInstruction);
+ }
+
+ return [hidden, newInstruction];
+ }
+
+ private parseParameter(instr: Instruction, parameter: string): boolean
+ {
+ let match = parameter.match(/\d*\.?\d*$/);
+ if(match !== null && match[0] === parameter && match.index === 0)
+ {
+ let val = parseFloat(parameter);
+ let paramObj = new NumberParameter(val);
+
+ instr.params.push(paramObj);
+ return true;
+ }
+
+ match = parameter.match(/[A-Za-z]/)
+ if(match !== null && match[0] === parameter && match.index === 0)
+ {
+ let paramObj = this.variables[parameter];
+ if(paramObj === undefined)
+ {
+ console.error("Variable \"" + parameter + "\" is not defined");
+ return false;
+ }
+
+ instr.params.push(paramObj);
+ return true;
+ }
+
+ match = parameter.match(/[A-Za-z]*\(.*\)/)
+ if(match !== null && match[0] === parameter && match.index === 0)
+ {
+ let paramObj = new InstructionParameter(this.parseInstruction(parameter)[1]);
+
+ instr.params.push(paramObj);
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/src/shapeStyle.ts b/src/shapeStyle.ts
index 174eaab..3f2ef5f 100644
--- a/src/shapeStyle.ts
+++ b/src/shapeStyle.ts
@@ -1,5 +1,4 @@
-
-export class ShapeStyle
+class ShapeStyle
{
public strokeWidth: number;
public strokeColor: string;
diff --git a/src/shapes.ts b/src/shapes.ts
index ea26817..4d2fd2d 100644
--- a/src/shapes.ts
+++ b/src/shapes.ts
@@ -1,5 +1,5 @@
-import { Vector2D } from "./vector.js"
-import { ShapeStyle } from "./shapeStyle.js";
+///
+///
abstract class Shape
{
diff --git a/src/vector.ts b/src/vector.ts
index 699eb8e..64a8fdb 100644
--- a/src/vector.ts
+++ b/src/vector.ts
@@ -1,4 +1,4 @@
-export class Vector2D
+class Vector2D
{
public x: number;
public y: number;
diff --git a/tsconfig.json b/tsconfig.json
index 90de336..2adc248 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,8 +1,7 @@
{
"compilerOptions": {
"target": "es6",
- // "outFile": "./out/lauchpioos.js",
- "outDir": "./out",
+ "outFile": "./out/geometry.js",
"sourceRoot": "./src",
"rootDir": "./src",
"sourceMap": true