From 2b43eb79ab5444c13870abc3b569018aed6cfa22 Mon Sep 17 00:00:00 2001 From: Funky Waddle Date: Sun, 23 Nov 2025 00:58:46 -0600 Subject: [PATCH] initial commit. --- core/bnf/.gitkeep | 0 core/bnf/expressions.bnf | 46 ++++++++++++ core/bnf/functions.bnf | 23 ++++++ core/bnf/identifiers.bnf | 13 ++++ core/bnf/main.bnf | 11 +++ core/bnf/statements.bnf | 20 ++++++ core/bnf/types.bnf | 29 ++++++++ core/compiler/.gitkeep | 0 core/lexicon/.gitkeep | 0 core/runtime/.gitkeep | 0 docs/language_spec/.gitkeep | 0 docs/module_development/.gitkeep | 0 examples/.gitkeep | 0 examples/example_class.wdl; | 43 +++++++++++ examples/example_inventory_class.wdl | 102 +++++++++++++++++++++++++++ tests/.gitkeep | 0 16 files changed, 287 insertions(+) create mode 100644 core/bnf/.gitkeep create mode 100644 core/bnf/expressions.bnf create mode 100644 core/bnf/functions.bnf create mode 100644 core/bnf/identifiers.bnf create mode 100644 core/bnf/main.bnf create mode 100644 core/bnf/statements.bnf create mode 100644 core/bnf/types.bnf create mode 100644 core/compiler/.gitkeep create mode 100644 core/lexicon/.gitkeep create mode 100644 core/runtime/.gitkeep create mode 100644 docs/language_spec/.gitkeep create mode 100644 docs/module_development/.gitkeep create mode 100644 examples/.gitkeep create mode 100644 examples/example_class.wdl; create mode 100644 examples/example_inventory_class.wdl create mode 100644 tests/.gitkeep diff --git a/core/bnf/.gitkeep b/core/bnf/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/core/bnf/expressions.bnf b/core/bnf/expressions.bnf new file mode 100644 index 0000000..a59ce74 --- /dev/null +++ b/core/bnf/expressions.bnf @@ -0,0 +1,46 @@ + ::= + | + | + | "(" ")" + | + + ::= + | "(" ")" + | .eq() + | .is() + | .not() + | .gt() + | .lt() + | .gte() + | .lte() + | Boolean.or(, ) + | Boolean.and(, ) + + + ::= "." "(" ? ")" + | ".sum()" + +Note: "set" is available on all base objects. +Methods listed after it are grouped by type: +group 1 are String methods, +group 2 are Integer/Decimal methods, +group 3 are Array methods, +group 4 are Integer Array methods + ::= "set" + | "length" | "reverse" | "split" | "format" | "search" | "concat" | "replace" + | "add" | "subtract" | "multiply" | "divide" | "mod" | "round" + | "remove" | "first" | "last" | "find" | "glue" | "contains" | "add" | "each" + | "sum" + | + + ::= "fn" "(" ? ")" "->" "[" "]" "{" * "}" + + ::= | | + + ::= + + + ::= '"' [^"]* '"' + + ::= "True" | "False" + + ::= "my." diff --git a/core/bnf/functions.bnf b/core/bnf/functions.bnf new file mode 100644 index 0000000..5a2d910 --- /dev/null +++ b/core/bnf/functions.bnf @@ -0,0 +1,23 @@ + ::= "fn" "on_create" "(" ? ")" "->" "[Null]" "{" * "}" + + ::= "fn" "on_destroy" "(" ? ")" "->" "[Null]" "{" * "}" + + ::= "@" "{" "}" + + ::= * + + ::= "fn" ";" + + ::= "fn" "{" * "}" + + ::= "(" ? ")" "->" + + ::= "-" | "" | "+" + + ::= "[" ("," )* "]" | "Runnable" + + ::= ("," )* [("," )*] + + ::= ":" + + ::= ":" "=" diff --git a/core/bnf/identifiers.bnf b/core/bnf/identifiers.bnf new file mode 100644 index 0000000..11c8ccf --- /dev/null +++ b/core/bnf/identifiers.bnf @@ -0,0 +1,13 @@ + ::= ( | )* + + ::= ("," )* + + ::= + + ::= | + + ::= "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z" + + ::= "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" + + ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" diff --git a/core/bnf/main.bnf b/core/bnf/main.bnf new file mode 100644 index 0000000..9831201 --- /dev/null +++ b/core/bnf/main.bnf @@ -0,0 +1,11 @@ + ::= * * + + ::= "use" ("." )* ";" + + ::= | + +import "types.bnf" +import "statements.bnf" +import "functions.bnf" +import "expressions.bnf" +import "identifiers.bnf" diff --git a/core/bnf/statements.bnf b/core/bnf/statements.bnf new file mode 100644 index 0000000..ccbb404 --- /dev/null +++ b/core/bnf/statements.bnf @@ -0,0 +1,20 @@ + ::= + | + | + | + | + | + + ::= ".set(" ")" ";" + + ::= "if" "(" ")" "{" * "}" ["else" "{" * "}"]? + + ::= "while" "(" ")" "{" * "}" + + ::= "(" ? ")" ";" + + ::= ("," )* + + ::= "rtn" ";" + + ::= "using" ".set(" ")" "{" * "}" diff --git a/core/bnf/types.bnf b/core/bnf/types.bnf new file mode 100644 index 0000000..272dedd --- /dev/null +++ b/core/bnf/types.bnf @@ -0,0 +1,29 @@ + ::= ["/" ] ["->" ] "{" "}" + + ::= ( | | | )* + + ::= "String" | "Integer" | "Decimal" | "Boolean" | | + + ::= | "Runnable" + + ::= [".set(" ")"] ";" + + ::= "fn" "{" * "}" + + ::= "(" ? ")" "->" + + ::= "-" | "" | "+" + + ::= "[" ("," )*] | "Runnable" + + ::= ("," )* [("," )*] + + ::= ":" + + ::= ":" "=" + + ::= "<>" + + ::= "fn" "on_create" "(" ? ")" "->" "[Null]" "{" * "}" + + ::= "fn" "on_destroy" "(" ? ")" "->" "[Null]" "{" * "}" diff --git a/core/compiler/.gitkeep b/core/compiler/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/core/lexicon/.gitkeep b/core/lexicon/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/core/runtime/.gitkeep b/core/runtime/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docs/language_spec/.gitkeep b/docs/language_spec/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docs/module_development/.gitkeep b/docs/module_development/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/examples/.gitkeep b/examples/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/examples/example_class.wdl; b/examples/example_class.wdl; new file mode 100644 index 0000000..ed321c5 --- /dev/null +++ b/examples/example_class.wdl; @@ -0,0 +1,43 @@ +use Vehicle.Car; +use Vehicle.Engine; + +Car/Equinox -> hasEngine { + String model; + Integer year; + Decimal fuelEfficiency; + Boolean isRunning; + Decimal fuelLevel; + Decimal mileage; + + fn on_create(String model, Integer year) -> [Null] { + my.model.set(model); + my.year.set(year); + my.fuelEfficiency.set(28.5); + my.isRunning.set(False); + my.fuelLevel.set(100.0); + my.mileage.set(0.0); + rtn Null; + } + + fn startEngine() -> [Boolean] { + Boolean engineStatus.set(Boolean.and(my.isRunning.not(True), my.fuelLevel.gt(0.0))); + my.isRunning.set(engineStatus); + rtn engineStatus; + } + + fn calculateFuelConsumption(Decimal distance) -> [Decimal] { + Decimal consumption.set(distance.divide(my.fuelEfficiency)); + rtn consumption; + } + + fn checkMaintenance() -> [Boolean] { + Boolean needsMaintenance.set(my.mileage.gte(50000.0)); + rtn needsMaintenance; + } + + +fn drive(Decimal miles) -> [Null] { + my.mileage.add(miles); + my.fuelLevel.subtract(my.calculateFuelConsumption(miles)); + rtn Null; + } +} diff --git a/examples/example_inventory_class.wdl b/examples/example_inventory_class.wdl new file mode 100644 index 0000000..e2919f3 --- /dev/null +++ b/examples/example_inventory_class.wdl @@ -0,0 +1,102 @@ +use Inventory.Base.InventoryInterface; +use Inventory.Base.PartsInventory; + +Inventory/PartsInventory -> InventoryInterface { + String<> partNames.set(<>); + Integer<> partQuantities.set(<>); + Decimal<> partPrices.set(<>); + + +fn on_create() -> [Null] { + // inventory initialized + } + + +fn on_destroy() -> [Null] { + my.partNames.set(<>); + my.partQuantities.set(<>); + my.partPrices.set(<>); + } + + -fn findPartIndex(partName:String) -> [Integer] { + Integer idx.set(-1); + my.partNames.each(name, i -> { + if (name.eq(partName)) { + idx.set(i); + } + }); + rtn idx; + } + + +fn addPart(partName:String, quantity:Integer, price:Decimal) -> [Boolean] { + Integer i.set(my.findPartIndex(partName)); + if (i.gte(0)) { + Integer current.set(my.partQuantities.get(i)); + my.partQuantities.remove(i); + my.partQuantities.add(current.add(quantity)); + my.partPrices.remove(i); + my.partPrices.add(price); + rtn True; + } else { + my.partNames.add(partName); + my.partQuantities.add(quantity); + my.partPrices.add(price); + rtn True; + } + } + + +fn removePart(partName:String, quantity:Integer) -> [Boolean] { + Integer i.set(my.findPartIndex(partName)); + if (i.lt(0)) { rtn False; } + + Integer current.set(my.partQuantities.get(i)); + if (current.lt(quantity)) { rtn False; } + + if (current.eq(quantity)) { + my.partNames.remove(i); + my.partQuantities.remove(i); + my.partPrices.remove(i); + } else { + my.partQuantities.remove(i); + my.partQuantities.add(current.subtract(quantity)); + } + rtn True; + } + + +fn getPartPrice(partName:String) -> [Decimal] { + Integer i.set(my.findPartIndex(partName)); + if (i.lt(0)) { rtn 0; } + rtn my.partPrices.get(i); + } + + +fn getTotalInventoryValue() -> [Decimal] { + Decimal total.set(0); + my.partNames.each(name, i -> { + Decimal value.set(my.partQuantities.get(i).multiply(my.partPrices.get(i))); + total.set(total.add(value)); + }); + rtn total; + } + + +fn getPartDetails(partName:String) -> [String] { + Integer i.set(my.findPartIndex(partName)); + if (i.lt(0)) { rtn ["Part not found"]; } + String details.set( + partName + .concat(" — Qty: ") + .concat(my.partQuantities.get(i).format()) + .concat(", Price: $") + .concat(my.partPrices.get(i).format()) + ); + rtn [details]; + } + + -fn ensureNonNegative(quantity:Integer) -> [Boolean] { + if (quantity.lt(0)) { rtn False; } + rtn True; + } + + fn audit_sample() { + // protected (no prefix) example: internal audit routine callable within package + String report.set("Inventory count: ".concat(my.partNames.length().format())); + rtn report; + } +} diff --git a/tests/.gitkeep b/tests/.gitkeep new file mode 100644 index 0000000..e69de29