🐐 Reviving this old project. Mainly adding tests and fixing bugs.
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,2 +1,5 @@
|
||||
.vscode/
|
||||
__pycache__/
|
||||
__pycache__/
|
||||
|
||||
.claude/
|
||||
CLAUDE.md
|
||||
12
README.md
12
README.md
@@ -7,7 +7,7 @@
|
||||
### Hello World
|
||||
```
|
||||
DESIGNA x VT "Hello World!"
|
||||
DICE x
|
||||
DICE(x)
|
||||
```
|
||||
|
||||
### Recursive Fibonacci number function
|
||||
@@ -99,7 +99,7 @@ Booleans are denoted with the keywords `VERITAS` for true and `FALSITAS` for fal
|
||||
Arrays are defined using square brackets (`[]`) and commas (`,`). An array of integers can also be initialized with the `VSQVE` keyword:
|
||||
|
||||
```
|
||||
DESIGNA x VT [1 VSQVE 10]
|
||||
DESIGNA x VT [I VSQVE X]
|
||||
```
|
||||
|
||||
## Conditionals
|
||||
@@ -110,10 +110,10 @@ If-then statements are denoted with the keywords `SI` (if) and `TVNC` (then). Th
|
||||
DESIGNA x VT VERITAS
|
||||
SI x TVNC {
|
||||
DICE(I)
|
||||
REDI(NVLLLVS)
|
||||
REDI(NVLLVS)
|
||||
}
|
||||
|
||||
DICE NVLLVS
|
||||
DICE(NVLLVS)
|
||||
|
||||
> I
|
||||
```
|
||||
@@ -209,12 +209,12 @@ PER y IN x FACE {
|
||||
```
|
||||
|
||||
## Functions
|
||||
Functions are defined with the `DEFINI` and `VT` keywords. The `REDI` keyword is used to return. `REDI` must have exactly one parameter. `REDI` can also be used to end the program, if used outside of a function.
|
||||
Functions are defined with the `DEFINI` and `VT` keywords. The `REDI` keyword is used to return. `REDI` can also be used to end the program, if used outside of a function.
|
||||
|
||||
Calling a function is done with the `INVOCA` keyword.
|
||||
|
||||
```
|
||||
DEFINI square x VT {
|
||||
DEFINI square(x) VT {
|
||||
REDI(x*x)
|
||||
}
|
||||
|
||||
|
||||
@@ -3,458 +3,506 @@ import random
|
||||
|
||||
from rply.token import BaseBox
|
||||
|
||||
from centvrion.values import Val, ValInt, ValStr, ValBool, ValList, ValNul, ValFunc
|
||||
|
||||
NUMERALS = {
|
||||
"I": 1,
|
||||
"IV": 4,
|
||||
"V": 5,
|
||||
"IX": 9,
|
||||
"X": 10,
|
||||
"XL": 40,
|
||||
"L": 50,
|
||||
"XC": 90,
|
||||
"C": 100,
|
||||
"CD": 400,
|
||||
"D": 500,
|
||||
"CM": 900,
|
||||
"M": 1000
|
||||
"I": 1,
|
||||
"IV": 4,
|
||||
"V": 5,
|
||||
"IX": 9,
|
||||
"X": 10,
|
||||
"XL": 40,
|
||||
"L": 50,
|
||||
"XC": 90,
|
||||
"C": 100,
|
||||
"CD": 400,
|
||||
"D": 500,
|
||||
"CM": 900,
|
||||
"M": 1000
|
||||
}
|
||||
|
||||
def rep_join(l):
|
||||
format_string = ',\n'.join(
|
||||
[repr(i) if not isinstance(i, str) else i for i in l]
|
||||
).replace('\n', '\n ')
|
||||
format_string = ',\n'.join(
|
||||
[repr(i) if not isinstance(i, str) else i for i in l]
|
||||
).replace('\n', '\n ')
|
||||
|
||||
if format_string != "":
|
||||
format_string = f"\n {format_string}\n"
|
||||
if format_string != "":
|
||||
format_string = f"\n {format_string}\n"
|
||||
|
||||
return format_string
|
||||
return format_string
|
||||
|
||||
def single_num_to_int(i, m):
|
||||
if i[-1] == "_":
|
||||
if not m:
|
||||
raise Exception(
|
||||
"Cannot calculate numbers above 3999 without 'MAGNVM' module"
|
||||
)
|
||||
if i[-1] == "_":
|
||||
if not m:
|
||||
raise ValueError(
|
||||
"Cannot calculate numbers above 3999 without 'MAGNVM' module"
|
||||
)
|
||||
|
||||
if i[0] != "I":
|
||||
raise Exception(
|
||||
"Cannot use 'I' with thousands operator, use 'M' instead"
|
||||
)
|
||||
if i[0] != "I":
|
||||
raise ValueError(
|
||||
"Cannot use 'I' with thousands operator, use 'M' instead"
|
||||
)
|
||||
|
||||
return 1000 * single_num_to_int(i[:-1], m)
|
||||
else:
|
||||
return NUMERALS[i]
|
||||
return 1000 * single_num_to_int(i[:-1], m)
|
||||
else:
|
||||
return NUMERALS[i]
|
||||
|
||||
def num_to_int(n, m):
|
||||
chars = re.findall(r"[IVXLCDM]_*", n)
|
||||
if ''.join(chars) != n:
|
||||
raise Exception("Invalid numeral", n)
|
||||
nums = [single_num_to_int(i, m) for i in chars]
|
||||
new_nums = nums.copy()
|
||||
for x, num in enumerate(nums[:-3]):
|
||||
if all(num == nums[x+i] for i in range(0,4)):
|
||||
raise Exception(n, "is not a valid roman numeral")
|
||||
chars = re.findall(r"[IVXLCDM]_*", n)
|
||||
if ''.join(chars) != n:
|
||||
raise ValueError("Invalid numeral", n)
|
||||
nums = [single_num_to_int(i, m) for i in chars]
|
||||
new_nums = nums.copy()
|
||||
for x, num in enumerate(nums[:-3]):
|
||||
if all(num == nums[x+i] for i in range(0,4)):
|
||||
raise ValueError(n, "is not a valid roman numeral")
|
||||
|
||||
while True:
|
||||
for x, num in enumerate(nums[:-1]):
|
||||
if num < nums[x+1]:
|
||||
if (not nums[x+1] % 5) and (num in [nums[x+1]/5, nums[x+1]/10]):
|
||||
new_nums[x] = nums[x+1] - num
|
||||
new_nums[x+1] = 0
|
||||
break
|
||||
else:
|
||||
raise Exception(n, "is not a valid roman numeral")
|
||||
|
||||
if new_nums != nums:
|
||||
nums = [i for i in new_nums if i != 0]
|
||||
new_nums = nums
|
||||
while True:
|
||||
for x, num in enumerate(nums[:-1]):
|
||||
if num < nums[x+1]:
|
||||
if (not nums[x+1] % 5) and (num in [nums[x+1]/5, nums[x+1]/10]):
|
||||
new_nums[x] = nums[x+1] - num
|
||||
new_nums[x+1] = 0
|
||||
break
|
||||
else:
|
||||
break
|
||||
raise ValueError(n, "is not a valid roman numeral")
|
||||
|
||||
if nums != sorted(nums)[::-1]:
|
||||
raise Exception(n, "is not a valid roman numeral")
|
||||
if new_nums != nums:
|
||||
nums = [i for i in new_nums if i != 0]
|
||||
new_nums = nums.copy()
|
||||
else:
|
||||
break
|
||||
|
||||
return sum(nums)
|
||||
if nums != sorted(nums)[::-1]:
|
||||
raise Exception(n, "is not a valid roman numeral")
|
||||
|
||||
return sum(nums)
|
||||
|
||||
def int_to_num(n, m):
|
||||
if n > 3999:
|
||||
if not m:
|
||||
raise Exception(
|
||||
"Cannot display numbers above 3999 without 'MAGNVM' module"
|
||||
)
|
||||
thousands_chars = re.findall(r"[IVXLCDM]_*", int_to_num(n//1000, m))
|
||||
thousands = ''.join([
|
||||
"M" if i == "I" else i+"_"
|
||||
for i in thousands_chars
|
||||
])
|
||||
if n > 3999:
|
||||
if not m:
|
||||
raise ValueError(
|
||||
"Cannot display numbers above 3999 without 'MAGNVM' module"
|
||||
)
|
||||
thousands_chars = re.findall(r"[IVXLCDM]_*", int_to_num(n//1000, m))
|
||||
thousands = ''.join([
|
||||
"M" if i == "I" else i+"_"
|
||||
for i in thousands_chars
|
||||
])
|
||||
|
||||
return thousands + int_to_num(n % 1000, m)
|
||||
else:
|
||||
nums = []
|
||||
while n > 0:
|
||||
for num, i in list(NUMERALS.items())[::-1]:
|
||||
if n >= i:
|
||||
nums.append(num)
|
||||
n -= i
|
||||
break
|
||||
return thousands + int_to_num(n % 1000, m)
|
||||
else:
|
||||
nums = []
|
||||
while n > 0:
|
||||
for num, i in list(NUMERALS.items())[::-1]:
|
||||
if n >= i:
|
||||
nums.append(num)
|
||||
n -= i
|
||||
break
|
||||
|
||||
return ''.join(nums)
|
||||
return ''.join(nums)
|
||||
|
||||
def make_string(n, m):
|
||||
if isinstance(n, str):
|
||||
return n
|
||||
elif isinstance(n, int):
|
||||
return int_to_num(n, m)
|
||||
elif isinstance(n, list):
|
||||
return f"[{' '.join([make_string(i, m) for i in n])}]"
|
||||
else:
|
||||
raise Exception(n)
|
||||
def make_string(val, magnvm=False):
|
||||
if isinstance(val, ValStr):
|
||||
return val.value()
|
||||
elif isinstance(val, ValInt):
|
||||
return int_to_num(val.value(), magnvm)
|
||||
elif isinstance(val, ValBool):
|
||||
return "VERVS" if val.value() else "FALSVS"
|
||||
elif isinstance(val, ValNul):
|
||||
return "NVLLVS"
|
||||
elif isinstance(val, ValList):
|
||||
inner = ' '.join(make_string(i, magnvm) for i in val.value())
|
||||
return f"[{inner}]"
|
||||
else:
|
||||
raise TypeError(f"Cannot display {val!r}")
|
||||
|
||||
class ExpressionStatement(BaseBox):
|
||||
def __init__(self, expression) -> None:
|
||||
self.expression = expression
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return self.expression.__repr__()
|
||||
class Node(BaseBox):
|
||||
def eval(self, vtable):
|
||||
return self._eval(vtable.copy())
|
||||
|
||||
def eval(self, vtable, ftable, modules):
|
||||
self.expression.eval(vtable.copy(), ftable.copy(), modules)
|
||||
return vtable, ftable
|
||||
def _eval(self, vtable):
|
||||
raise NotImplementedError
|
||||
|
||||
class DataArray(BaseBox):
|
||||
def __init__(self, content) -> None:
|
||||
self.content = content
|
||||
|
||||
def __repr__(self) -> str:
|
||||
content_string = rep_join(self.content)
|
||||
return f"Array([{content_string}])"
|
||||
class ExpressionStatement(Node):
|
||||
def __init__(self, expression) -> None:
|
||||
self.expression = expression
|
||||
|
||||
def eval(self, vtable, ftable, modules):
|
||||
content = [i.eval(vtable, ftable, modules) for i in self.content]
|
||||
return content
|
||||
def __repr__(self) -> str:
|
||||
return self.expression.__repr__()
|
||||
|
||||
class DataRangeArray(BaseBox):
|
||||
def __init__(self, from_value, to_value) -> None:
|
||||
self.from_value = from_value
|
||||
self.to_value = to_value
|
||||
def _eval(self, vtable):
|
||||
return self.expression.eval(vtable)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
content_string = rep_join([self.from_value, self.to_value])
|
||||
return f"RangeArray([{content_string}])"
|
||||
|
||||
def eval(self, *_):
|
||||
content = list(range(self.from_value.eval(), self.to_value.eval()))
|
||||
return content
|
||||
class DataArray(Node):
|
||||
def __init__(self, content) -> None:
|
||||
self.content = content
|
||||
|
||||
class String(BaseBox):
|
||||
def __init__(self, value) -> None:
|
||||
self.value = value
|
||||
def __repr__(self) -> str:
|
||||
content_string = rep_join(self.content)
|
||||
return f"Array([{content_string}])"
|
||||
|
||||
def __repr__(self):
|
||||
return f"String({self.value})"
|
||||
def _eval(self, vtable):
|
||||
vals = []
|
||||
for item in self.content:
|
||||
vtable, val = item.eval(vtable)
|
||||
vals.append(val)
|
||||
return vtable, ValList(vals)
|
||||
|
||||
def eval(self, *_):
|
||||
return self.value
|
||||
|
||||
class Numeral(BaseBox):
|
||||
def __init__(self, value) -> None:
|
||||
self.value = value
|
||||
class DataRangeArray(Node):
|
||||
def __init__(self, from_value, to_value) -> None:
|
||||
self.from_value = from_value
|
||||
self.to_value = to_value
|
||||
|
||||
def __repr__(self):
|
||||
return f"Numeral({self.value})"
|
||||
def __repr__(self) -> str:
|
||||
content_string = rep_join([self.from_value, self.to_value])
|
||||
return f"RangeArray([{content_string}])"
|
||||
|
||||
def eval(self, *args):
|
||||
return num_to_int(self.value, "MAGNVM" in args[2])
|
||||
def _eval(self, vtable):
|
||||
vtable, from_val = self.from_value.eval(vtable)
|
||||
vtable, to_val = self.to_value.eval(vtable)
|
||||
return vtable, ValList([ValInt(i) for i in range(from_val.value(), to_val.value())])
|
||||
|
||||
class Bool(BaseBox):
|
||||
def __init__(self, value) -> None:
|
||||
self.value = value
|
||||
|
||||
def __repr__(self):
|
||||
return f"Bool({self.value})"
|
||||
class String(Node):
|
||||
def __init__(self, value) -> None:
|
||||
self.value = value
|
||||
|
||||
def __repr__(self):
|
||||
return f"String({self.value})"
|
||||
|
||||
def _eval(self, vtable):
|
||||
return vtable, ValStr(self.value)
|
||||
|
||||
|
||||
class Numeral(Node):
|
||||
def __init__(self, value) -> None:
|
||||
self.value = value
|
||||
|
||||
def __repr__(self):
|
||||
return f"Numeral({self.value})"
|
||||
|
||||
def _eval(self, vtable):
|
||||
return vtable, ValInt(num_to_int(self.value, "MAGNVM" in vtable["#modules"]))
|
||||
|
||||
|
||||
class Bool(Node):
|
||||
def __init__(self, value) -> None:
|
||||
self.value = value
|
||||
|
||||
def __repr__(self):
|
||||
return f"Bool({self.value})"
|
||||
|
||||
def _eval(self, vtable):
|
||||
return vtable, ValBool(self.value)
|
||||
|
||||
def eval(self, *_):
|
||||
return self.value
|
||||
|
||||
class ModuleCall(BaseBox):
|
||||
def __init__(self, module_name) -> None:
|
||||
self.module_name = module_name
|
||||
def __init__(self, module_name) -> None:
|
||||
self.module_name = module_name
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"{self.module_name}"
|
||||
def __repr__(self) -> str:
|
||||
return f"{self.module_name}"
|
||||
|
||||
class ID(BaseBox):
|
||||
def __init__(self, name: str) -> None:
|
||||
self.name = name
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"ID({self.name})"
|
||||
class ID(Node):
|
||||
def __init__(self, name: str) -> None:
|
||||
self.name = name
|
||||
|
||||
def eval(self, vtable, *_):
|
||||
return vtable[self.name]
|
||||
def __repr__(self) -> str:
|
||||
return f"ID({self.name})"
|
||||
|
||||
class Designa(BaseBox):
|
||||
def __init__(self, variable: ID, value) -> None:
|
||||
self.id = variable
|
||||
self.value = value
|
||||
def _eval(self, vtable):
|
||||
return vtable, vtable[self.name]
|
||||
|
||||
def __repr__(self) -> str:
|
||||
id_string = repr(self.id).replace('\n', '\n ')
|
||||
value_string = repr(self.value).replace('\n', '\n ')
|
||||
return f"Designa(\n {id_string},\n {value_string}\n)"
|
||||
|
||||
def eval(self, vtable, ftable, modules):
|
||||
vtable[self.id.name] = self.value.eval(
|
||||
vtable.copy(), ftable.copy(), modules
|
||||
class Designa(Node):
|
||||
def __init__(self, variable: ID, value) -> None:
|
||||
self.id = variable
|
||||
self.value = value
|
||||
|
||||
def __repr__(self) -> str:
|
||||
id_string = repr(self.id).replace('\n', '\n ')
|
||||
value_string = repr(self.value).replace('\n', '\n ')
|
||||
return f"Designa(\n {id_string},\n {value_string}\n)"
|
||||
|
||||
def _eval(self, vtable):
|
||||
vtable, val = self.value.eval(vtable)
|
||||
vtable[self.id.name] = val
|
||||
return vtable, ValNul()
|
||||
|
||||
|
||||
class Defini(Node):
|
||||
def __init__(self, name, parameters, statements) -> None:
|
||||
self.name = name
|
||||
self.parameters = parameters
|
||||
self.statements = statements
|
||||
|
||||
def __repr__(self) -> str:
|
||||
parameter_string = f"parameters([{rep_join(self.parameters)}])"
|
||||
statements_string = f"statements([{rep_join(self.statements)}])"
|
||||
def_string = rep_join(
|
||||
[f"{repr(self.name)}", parameter_string, statements_string]
|
||||
)
|
||||
return f"Defini({def_string})"
|
||||
|
||||
def _eval(self, vtable):
|
||||
vtable[self.name.name] = ValFunc(self.parameters, self.statements)
|
||||
return vtable, ValNul()
|
||||
|
||||
|
||||
class Redi(Node):
|
||||
def __init__(self, values) -> None:
|
||||
self.values = values
|
||||
|
||||
def __repr__(self) -> str:
|
||||
values_string = f"[{rep_join(self.values)}]"
|
||||
return f"Redi({values_string})"
|
||||
|
||||
def _eval(self, vtable):
|
||||
vals = []
|
||||
for v in self.values:
|
||||
vtable, val = v.eval(vtable)
|
||||
vals.append(val)
|
||||
if len(vals) == 1:
|
||||
vtable["#return"] = vals[0]
|
||||
else:
|
||||
vtable["#return"] = ValList(vals)
|
||||
return vtable, ValNul()
|
||||
|
||||
|
||||
class Erumpe(Node):
|
||||
def __repr__(self) -> str:
|
||||
return "Erumpe()"
|
||||
|
||||
def _eval(self, vtable):
|
||||
vtable["#break"] = True
|
||||
return vtable, ValNul()
|
||||
|
||||
|
||||
class Nullus(Node):
|
||||
def __repr__(self) -> str:
|
||||
return "Nullus()"
|
||||
|
||||
def _eval(self, vtable):
|
||||
return vtable, ValNul()
|
||||
|
||||
|
||||
class BinOp(Node):
|
||||
def __init__(self, left, right, op) -> None:
|
||||
self.left = left
|
||||
self.right = right
|
||||
self.op = op
|
||||
|
||||
def __repr__(self) -> str:
|
||||
binop_string = rep_join([self.left, self.right, self.op])
|
||||
return f"BinOp({binop_string})"
|
||||
|
||||
def _eval(self, vtable):
|
||||
vtable, left = self.left.eval(vtable)
|
||||
vtable, right = self.right.eval(vtable)
|
||||
lv, rv = left.value(), right.value()
|
||||
match self.op:
|
||||
case "SYMBOL_PLUS":
|
||||
return vtable, ValInt(lv + rv)
|
||||
case "SYMBOL_MINUS":
|
||||
return vtable, ValInt(lv - rv)
|
||||
case "SYMBOL_TIMES":
|
||||
return vtable, ValInt(lv * rv)
|
||||
case "SYMBOL_DIVIDE":
|
||||
# TODO: Fractio
|
||||
return vtable, ValInt(lv // rv)
|
||||
case "KEYWORD_MINVS":
|
||||
return vtable, ValBool(lv < rv)
|
||||
case "KEYWORD_PLVS":
|
||||
return vtable, ValBool(lv > rv)
|
||||
case "KEYWORD_EST":
|
||||
return vtable, ValBool(lv == rv)
|
||||
case "KEYWORD_ET":
|
||||
return vtable, ValBool(bool(lv) and bool(rv))
|
||||
case "KEYWORD_AVT":
|
||||
return vtable, ValBool(bool(lv) or bool(rv))
|
||||
case _:
|
||||
raise Exception(self.op)
|
||||
|
||||
|
||||
class SiStatement(Node):
|
||||
def __init__(self, test, statements, else_part) -> None:
|
||||
self.test = test
|
||||
self.statements = statements
|
||||
self.else_part = else_part
|
||||
|
||||
def __repr__(self) -> str:
|
||||
test = repr(self.test)
|
||||
statements = f"statements([{rep_join(self.statements)}])"
|
||||
else_part = f"statements([{rep_join(self.else_part) if self.else_part else ''}])"
|
||||
si_string = rep_join([test, statements, else_part])
|
||||
return f"Si({si_string})"
|
||||
|
||||
def _eval(self, vtable):
|
||||
vtable, cond = self.test.eval(vtable)
|
||||
last_val = ValNul()
|
||||
if cond:
|
||||
for statement in self.statements:
|
||||
vtable, last_val = statement.eval(vtable)
|
||||
elif self.else_part:
|
||||
for statement in self.else_part:
|
||||
vtable, last_val = statement.eval(vtable)
|
||||
return vtable, last_val
|
||||
|
||||
|
||||
class DumStatement(Node):
|
||||
def __init__(self, test, statements) -> None:
|
||||
self.test = test
|
||||
self.statements = statements
|
||||
|
||||
def __repr__(self) -> str:
|
||||
test = repr(self.test)
|
||||
statements = f"statements([{rep_join(self.statements)}])"
|
||||
dum_string = rep_join([test, statements])
|
||||
return f"Dum({dum_string})"
|
||||
|
||||
def _eval(self, vtable):
|
||||
last_val = ValNul()
|
||||
vtable, cond = self.test.eval(vtable)
|
||||
while not cond:
|
||||
for statement in self.statements:
|
||||
vtable, val = statement.eval(vtable)
|
||||
if vtable["#break"]:
|
||||
break
|
||||
last_val = val
|
||||
if vtable["#break"]:
|
||||
vtable["#break"] = False
|
||||
break
|
||||
vtable, cond = self.test.eval(vtable)
|
||||
return vtable, last_val
|
||||
|
||||
|
||||
class PerStatement(Node):
|
||||
def __init__(self, data_list, variable_name, statements) -> None:
|
||||
self.data_list = data_list
|
||||
self.variable_name = variable_name
|
||||
self.statements = statements
|
||||
|
||||
def __repr__(self) -> str:
|
||||
test = repr(self.data_list)
|
||||
variable_name = repr(self.variable_name)
|
||||
statements = f"statements([{rep_join(self.statements)}])"
|
||||
dum_string = rep_join([test, variable_name, statements])
|
||||
return f"Per({dum_string})"
|
||||
|
||||
def _eval(self, vtable):
|
||||
vtable, array = self.data_list.eval(vtable)
|
||||
variable_name = self.variable_name.name
|
||||
last_val = ValNul()
|
||||
for item in array:
|
||||
vtable[variable_name] = item
|
||||
for statement in self.statements:
|
||||
vtable, val = statement.eval(vtable)
|
||||
if vtable["#break"]:
|
||||
break
|
||||
last_val = val
|
||||
if vtable["#break"]:
|
||||
vtable["#break"] = False
|
||||
break
|
||||
return vtable, last_val
|
||||
|
||||
|
||||
class Invoca(Node):
|
||||
def __init__(self, name, parameters) -> None:
|
||||
self.name = name
|
||||
self.parameters = parameters
|
||||
|
||||
def __repr__(self) -> str:
|
||||
parameters_string = f"parameters([{rep_join(self.parameters)}])"
|
||||
invoca_string = rep_join([self.name, parameters_string])
|
||||
return f"Invoca({invoca_string})"
|
||||
|
||||
def _eval(self, vtable):
|
||||
params = [p.eval(vtable)[1] for p in self.parameters]
|
||||
func = vtable[self.name.name]
|
||||
if len(params) != len(func.params):
|
||||
raise TypeError(
|
||||
f"{self.name.name} expects {len(func.params)} argument(s), got {len(params)}"
|
||||
)
|
||||
func_vtable = vtable.copy()
|
||||
for i, param in enumerate(func.params):
|
||||
func_vtable[param.name] = params[i]
|
||||
func_vtable["#return"] = None
|
||||
for statement in func.body:
|
||||
func_vtable, _ = statement.eval(func_vtable)
|
||||
if func_vtable["#return"] is not None:
|
||||
return vtable, func_vtable["#return"]
|
||||
return vtable, ValNul()
|
||||
|
||||
|
||||
class BuiltIn(Node):
|
||||
def __init__(self, builtin, parameters) -> None:
|
||||
self.builtin = builtin
|
||||
self.parameters = parameters
|
||||
|
||||
def __repr__(self) -> str:
|
||||
parameter_string = f"parameters([{rep_join(self.parameters)}])"
|
||||
builtin_string = rep_join([self.builtin, parameter_string])
|
||||
return f"Builtin({builtin_string})"
|
||||
|
||||
def _eval(self, vtable):
|
||||
params = [p.eval(vtable)[1] for p in self.parameters]
|
||||
magnvm = "MAGNVM" in vtable["#modules"]
|
||||
|
||||
match self.builtin:
|
||||
case "AVDI_NVMERVS":
|
||||
return vtable, ValInt(num_to_int(input(), magnvm))
|
||||
case "AVDI":
|
||||
return vtable, ValStr(input())
|
||||
case "DICE":
|
||||
print_string = ' '.join(
|
||||
make_string(i, magnvm) for i in params
|
||||
)
|
||||
return vtable, ftable
|
||||
print(print_string)
|
||||
return vtable, ValStr(print_string)
|
||||
case "ERVMPE":
|
||||
vtable["#break"] = True
|
||||
return vtable, ValNul()
|
||||
case "FORTIS_NVMERVS":
|
||||
if "FORS" not in vtable["#modules"]:
|
||||
raise ValueError(
|
||||
"Cannot use 'FORTIS_NVMERVS' without module 'FORS'"
|
||||
)
|
||||
return vtable, ValInt(random.randint(params[0].value(), params[1].value()))
|
||||
case "FORTIS_ELECTIONIS":
|
||||
if "FORS" not in vtable["#modules"]:
|
||||
raise ValueError(
|
||||
"Cannot use 'FORTIS_ELECTIONIS' without module 'FORS'"
|
||||
)
|
||||
return vtable, params[0].value()[random.randint(0, len(params[0].value()) - 1)]
|
||||
case "LONGITVDO":
|
||||
return vtable, ValInt(len(params[0].value()))
|
||||
case _:
|
||||
raise NotImplementedError(self.builtin)
|
||||
|
||||
class Defini(BaseBox):
|
||||
def __init__(self, name, parameters, statements) -> None:
|
||||
self.name = name
|
||||
self.parameters = parameters
|
||||
self.statements = statements
|
||||
|
||||
def __repr__(self) -> str:
|
||||
parameter_string = f"parameters([{rep_join(self.parameters)}])"
|
||||
statements_string = f"statements([{rep_join(self.statements)}])"
|
||||
def_string = rep_join(
|
||||
[f"{repr(self.name)}", parameter_string, statements_string]
|
||||
)
|
||||
return f"Defini({def_string})"
|
||||
|
||||
def eval(self, vtable, ftable, _):
|
||||
ftable[self.name.name] = (
|
||||
self.parameters, self.statements
|
||||
)
|
||||
return vtable, ftable
|
||||
|
||||
class Redi(BaseBox):
|
||||
def __init__(self, values) -> None:
|
||||
self.values = values
|
||||
|
||||
def __repr__(self) -> str:
|
||||
values_string = f"[{rep_join(self.values)}]"
|
||||
return f"Redi({values_string})"
|
||||
|
||||
def eval(self, vtable, ftable, modules):
|
||||
values = [
|
||||
i.eval(vtable.copy(), ftable.copy(), modules)
|
||||
for i in self.values
|
||||
]
|
||||
if len(values) == 1:
|
||||
vtable["REDI"] = values[0]
|
||||
else:
|
||||
vtable["REDI"] = values
|
||||
return vtable, ftable
|
||||
|
||||
class Erumpe(BaseBox):
|
||||
def __repr__(self) -> str:
|
||||
return "Erumpe()"
|
||||
|
||||
def eval(self, vtable, ftable, _):
|
||||
vtable["ERVMPE"] = True
|
||||
return vtable, ftable
|
||||
|
||||
class Nullus(BaseBox):
|
||||
def __repr__(self) -> str:
|
||||
return "Nullus()"
|
||||
|
||||
def eval(self, *_):
|
||||
return 0
|
||||
|
||||
class BinOp(BaseBox):
|
||||
def __init__(self, left, right, op) -> None:
|
||||
self.left = left
|
||||
self.right = right
|
||||
self.op = op
|
||||
|
||||
def __repr__(self) -> str:
|
||||
binop_string = rep_join([self.left, self.right, self.op])
|
||||
return f"BinOp({binop_string})"
|
||||
|
||||
def eval(self, vtable, ftable, modules):
|
||||
left = self.left.eval(vtable.copy(), ftable.copy(), modules)
|
||||
right = self.right.eval(vtable.copy(), ftable.copy(), modules)
|
||||
match self.op:
|
||||
case "SYMBOL_PLUS":
|
||||
return left + right
|
||||
case "SYMBOL_MINUS":
|
||||
return left - right
|
||||
case "SYMBOL_TIMES":
|
||||
return left * right
|
||||
case "SYMBOL_DIVIDE":
|
||||
# TODO: Fractio
|
||||
return left // right
|
||||
case "KEYWORD_MINVS":
|
||||
return left < right
|
||||
case "KEYWORD_PLVS":
|
||||
return left > right
|
||||
case "KEYWORD_EST":
|
||||
return left == right
|
||||
case _:
|
||||
raise Exception(self.op)
|
||||
|
||||
class SiStatement(BaseBox):
|
||||
def __init__(self, test, statements, else_part) -> None:
|
||||
self.test = test
|
||||
self.statements = statements
|
||||
self.else_part = else_part
|
||||
|
||||
def __repr__(self) -> str:
|
||||
test = repr(self.test)
|
||||
statements = f"statements([{rep_join(self.statements)}])"
|
||||
else_part = f"statements([{rep_join(self.else_part)}])"
|
||||
si_string = rep_join([test, statements, else_part])
|
||||
return f"Si({si_string})"
|
||||
|
||||
def eval(self, vtable, ftable, modules):
|
||||
if self.test.eval(vtable, ftable, modules):
|
||||
for statement in self.statements:
|
||||
vtable, ftable = statement.eval(
|
||||
vtable, ftable, modules
|
||||
)
|
||||
else:
|
||||
for statement in self.else_part:
|
||||
vtable, ftable = statement.eval(
|
||||
vtable, ftable, modules
|
||||
)
|
||||
|
||||
return vtable, ftable
|
||||
|
||||
class DumStatement(BaseBox):
|
||||
def __init__(self, test, statements) -> None:
|
||||
self.test = test
|
||||
self.statements = statements
|
||||
|
||||
def __repr__(self) -> str:
|
||||
test = repr(self.test)
|
||||
statements = f"statements([{rep_join(self.statements)}])"
|
||||
dum_string = rep_join([test, statements])
|
||||
return f"Dum({dum_string})"
|
||||
|
||||
def eval(self, vtable, ftable, modules):
|
||||
while not self.test.eval(vtable, ftable, modules):
|
||||
for statement in self.statements:
|
||||
vtable, ftable = statement.eval(
|
||||
vtable, ftable, modules
|
||||
)
|
||||
if vtable["ERVMPE"]:
|
||||
break
|
||||
|
||||
if vtable["ERVMPE"]:
|
||||
vtable["ERVMPE"] = False
|
||||
break
|
||||
|
||||
return vtable, ftable
|
||||
|
||||
class PerStatement(BaseBox):
|
||||
def __init__(self, data_list, variable_name, statements) -> None:
|
||||
self.data_list = data_list
|
||||
self.variable_name = variable_name
|
||||
self.statements = statements
|
||||
|
||||
def __repr__(self) -> str:
|
||||
test = repr(self.data_list)
|
||||
variable_name = repr(self.variable_name)
|
||||
statements = f"statements([{rep_join(self.statements)}])"
|
||||
dum_string = rep_join([test, variable_name, statements])
|
||||
return f"Per({dum_string})"
|
||||
|
||||
def eval(self, vtable, ftable, modules):
|
||||
data_array = self.data_list.eval(vtable, ftable, modules)
|
||||
variable_name = self.variable_name.name
|
||||
for i in data_array:
|
||||
vtable[variable_name] = i
|
||||
for statement in self.statements:
|
||||
vtable, ftable = statement.eval(
|
||||
vtable, ftable, modules
|
||||
)
|
||||
if vtable["ERVMPE"]:
|
||||
break
|
||||
|
||||
if vtable["ERVMPE"]:
|
||||
vtable["ERVMPE"] = False
|
||||
break
|
||||
|
||||
return vtable, ftable
|
||||
|
||||
class Invoca(BaseBox):
|
||||
def __init__(self, name, parameters) -> None:
|
||||
self.name = name
|
||||
self.parameters = parameters
|
||||
|
||||
def __repr__(self) -> str:
|
||||
parameters_string = f"parameters([{rep_join(self.parameters)}])"
|
||||
invoca_string = rep_join([self.name, parameters_string])
|
||||
return f"Invoca({invoca_string})"
|
||||
|
||||
def eval(self, vtable, ftable, modules):
|
||||
parameters = [
|
||||
i.eval(vtable.copy(), ftable.copy(), modules)
|
||||
for i in self.parameters
|
||||
]
|
||||
vtable_copy = vtable.copy()
|
||||
function = ftable[self.name.name]
|
||||
for i, parameter in enumerate(function[0]):
|
||||
vtable_copy[parameter.name] = parameters[i]
|
||||
|
||||
vtable_copy["REDI"] = None
|
||||
for statement in function[1]:
|
||||
statement.eval(vtable_copy, ftable, modules)
|
||||
if vtable_copy["REDI"] is not None:
|
||||
return vtable_copy["REDI"]
|
||||
|
||||
class BuiltIn(BaseBox):
|
||||
def __init__(self, builtin, parameters) -> None:
|
||||
self.builtin = builtin
|
||||
self.parameters = parameters
|
||||
|
||||
def __repr__(self) -> str:
|
||||
parameter_string = f"parameters([{rep_join(self.parameters)}])"
|
||||
builtin_string = rep_join([self.builtin, parameter_string])
|
||||
return f"Builtin({builtin_string})"
|
||||
|
||||
def eval(self, vtable, ftable, modules):
|
||||
parameters = [
|
||||
i.eval(vtable.copy(), ftable.copy(), modules)
|
||||
for i in self.parameters
|
||||
]
|
||||
|
||||
match self.builtin:
|
||||
case "AVDI_NVMERVS":
|
||||
return num_to_int(input(), "MAGNVM" in modules)
|
||||
case "DICE":
|
||||
print(' '.join(
|
||||
make_string(i, "MAGNVM" in modules) for i in parameters)
|
||||
)
|
||||
return None
|
||||
case "ERVMPE":
|
||||
vtable["ERVMPE"] = True
|
||||
return None
|
||||
case "FORTIS_NVMERVS":
|
||||
if "FORS" not in modules:
|
||||
raise Exception(
|
||||
"Cannot use 'FORTIS_NVMERVS' without module 'FORS'"
|
||||
)
|
||||
return random.randint(parameters[0], parameters[1])
|
||||
case _:
|
||||
raise Exception(self.builtin)
|
||||
|
||||
class Program(BaseBox):
|
||||
def __init__(self, module_calls: list[ModuleCall], statements) -> None:
|
||||
self.modules = module_calls
|
||||
self.statements = statements
|
||||
def __init__(self, module_calls: list[ModuleCall], statements) -> None:
|
||||
self.modules = module_calls
|
||||
self.statements = statements
|
||||
|
||||
def __repr__(self) -> str:
|
||||
modules_string = f"modules([{rep_join(self.modules)}])"
|
||||
statements_string = f"statements([{rep_join(self.statements)}])"
|
||||
return f"{modules_string},\n{statements_string}"
|
||||
def __repr__(self) -> str:
|
||||
modules_string = f"modules([{rep_join(self.modules)}])"
|
||||
statements_string = f"statements([{rep_join(self.statements)}])"
|
||||
return f"{modules_string},\n{statements_string}"
|
||||
|
||||
def eval(self, *_):
|
||||
vtable = {"ERVMPE": False}
|
||||
ftable = {}
|
||||
modules = [module.module_name for module in self.modules]
|
||||
|
||||
for statement in self.statements:
|
||||
vtable, ftable = statement.eval(vtable, ftable, modules)
|
||||
def eval(self, *_):
|
||||
vtable = {
|
||||
"#break": False,
|
||||
"#return": None,
|
||||
"#modules": [m.module_name for m in self.modules],
|
||||
}
|
||||
last_val = ValNul()
|
||||
for statement in self.statements:
|
||||
vtable, last_val = statement.eval(vtable)
|
||||
return last_val
|
||||
|
||||
@@ -3,88 +3,92 @@ from rply import LexerGenerator
|
||||
valid_characters = '|'.join(list("abcdefghiklmnopqrstvxyz_"))
|
||||
|
||||
keyword_tokens = [("KEYWORD_"+i, i) for i in [
|
||||
"ALVID",
|
||||
"DEFINI",
|
||||
"DESIGNA",
|
||||
"DONICVM",
|
||||
"DVM",
|
||||
"ERVMPE",
|
||||
"EST",
|
||||
"FACE",
|
||||
"FALSITAS",
|
||||
"INVOCA",
|
||||
"IN",
|
||||
"MINVS",
|
||||
"NVLLVS",
|
||||
"PER",
|
||||
"PLVS",
|
||||
"REDI",
|
||||
"SI",
|
||||
"TVNC",
|
||||
"VSQVE",
|
||||
"VT",
|
||||
"VERITAS",
|
||||
"CVM"
|
||||
"ALVID",
|
||||
"AVT",
|
||||
"DEFINI",
|
||||
"DESIGNA",
|
||||
"DONICVM",
|
||||
"DVM",
|
||||
"ERVMPE",
|
||||
"EST",
|
||||
"ET",
|
||||
"FACE",
|
||||
"FALSITAS",
|
||||
"INVOCA",
|
||||
"IN",
|
||||
"MINVS",
|
||||
"NVLLVS",
|
||||
"PER",
|
||||
"PLVS",
|
||||
"REDI",
|
||||
"SI",
|
||||
"TVNC",
|
||||
"VSQVE",
|
||||
"VT",
|
||||
"VERITAS",
|
||||
"CVM"
|
||||
]]
|
||||
|
||||
builtin_tokens = [("BUILTIN", i) for i in [
|
||||
"AVDI_NVMERVS",
|
||||
"AVDI",
|
||||
"DICE",
|
||||
"FORTIS_NVMERVS",
|
||||
"FORTIS_ELECTIONIS",
|
||||
"LONGITVDO"
|
||||
"AVDI_NVMERVS",
|
||||
"AVDI",
|
||||
"DICE",
|
||||
"FORTIS_NVMERVS",
|
||||
"FORTIS_ELECTIONIS",
|
||||
"LONGITVDO"
|
||||
]]
|
||||
|
||||
data_tokens = [
|
||||
("DATA_STRING", r"\".*?\""),
|
||||
("DATA_NUMERAL", r"[IVXLCDM]+")
|
||||
("DATA_STRING", r"(\".*?\"|'.*?')"),
|
||||
("DATA_NUMERAL", r"[IVXLCDM][IVXLCDM_]*")
|
||||
]
|
||||
|
||||
module_tokens = [("MODULE", i) for i in [
|
||||
"FORS",
|
||||
"FRACTIO",
|
||||
"MAGNVM",
|
||||
"SVBNVLLA"
|
||||
"FORS",
|
||||
"FRACTIO",
|
||||
"MAGNVM",
|
||||
"SVBNVLLA"
|
||||
]]
|
||||
|
||||
symbol_tokens = [
|
||||
("SYMBOL_LPARENS", r"\("),
|
||||
("SYMBOL_RPARENS", r"\)"),
|
||||
("SYMBOL_LBRACKET", r"\["),
|
||||
("SYMBOL_RBRACKET", r"\]"),
|
||||
("SYMBOL_LCURL", r"\{"),
|
||||
("SYMBOL_RCURL", r"\}"),
|
||||
("SYMBOL_PLUS", r"\+"),
|
||||
("SYMBOL_MINUS", r"\-"),
|
||||
("SYMBOL_TIMES", r"\*"),
|
||||
("SYMBOL_DIVIDE", r"\/"),
|
||||
("SYMBOL_COMMA", r",")
|
||||
("SYMBOL_LPARENS", r"\("),
|
||||
("SYMBOL_RPARENS", r"\)"),
|
||||
("SYMBOL_LBRACKET", r"\["),
|
||||
("SYMBOL_RBRACKET", r"\]"),
|
||||
("SYMBOL_LCURL", r"\{"),
|
||||
("SYMBOL_RCURL", r"\}"),
|
||||
("SYMBOL_PLUS", r"\+"),
|
||||
("SYMBOL_MINUS", r"\-"),
|
||||
("SYMBOL_TIMES", r"\*"),
|
||||
("SYMBOL_DIVIDE", r"\/"),
|
||||
("SYMBOL_COMMA", r",")
|
||||
]
|
||||
|
||||
whitespace_tokens = [
|
||||
("NEWLINE", r"\n+")
|
||||
("NEWLINE", r"\n+")
|
||||
]
|
||||
|
||||
all_tokens = (
|
||||
keyword_tokens +
|
||||
builtin_tokens +
|
||||
module_tokens +
|
||||
symbol_tokens +
|
||||
data_tokens +
|
||||
whitespace_tokens +
|
||||
[("ID", f"({valid_characters})+")]
|
||||
keyword_tokens +
|
||||
builtin_tokens +
|
||||
module_tokens +
|
||||
symbol_tokens +
|
||||
data_tokens +
|
||||
whitespace_tokens +
|
||||
[("ID", f"({valid_characters})+")]
|
||||
)
|
||||
|
||||
class Lexer():
|
||||
def __init__(self):
|
||||
self.lexer = LexerGenerator()
|
||||
def __init__(self):
|
||||
self.lexer = LexerGenerator()
|
||||
|
||||
def _add_tokens(self):
|
||||
for token in all_tokens:
|
||||
self.lexer.add(*token)
|
||||
self.lexer.ignore(r" +")
|
||||
def _add_tokens(self):
|
||||
for token in all_tokens:
|
||||
self.lexer.add(*token)
|
||||
self.lexer.ignore(r" +")
|
||||
self.lexer.ignore(r'//[^\n]*')
|
||||
self.lexer.ignore(r'/\*[\s\S]*?\*/')
|
||||
|
||||
def get_lexer(self):
|
||||
self._add_tokens()
|
||||
return self.lexer.build()
|
||||
def get_lexer(self):
|
||||
self._add_tokens()
|
||||
return self.lexer.build()
|
||||
|
||||
@@ -6,203 +6,212 @@ from . import ast_nodes
|
||||
ALL_TOKENS = list(set([i[0] for i in all_tokens]))
|
||||
|
||||
class Parser():
|
||||
def __init__(self):
|
||||
self.pg = ParserGenerator(
|
||||
ALL_TOKENS,
|
||||
precedence=[
|
||||
('left', ["KEYWORD_PLVS", "KEYWORD_MINVS", "KEYWORD_EST"]),
|
||||
('left', ["SYMBOL_PLUS", "SYMBOL_MINUS"]),
|
||||
('left', ["SYMBOL_TIMES", "SYMBOL_DIVIDE"])
|
||||
]
|
||||
)
|
||||
def __init__(self):
|
||||
self.pg = ParserGenerator(
|
||||
ALL_TOKENS,
|
||||
precedence=[
|
||||
('left', ["KEYWORD_AVT"]),
|
||||
('left', ["KEYWORD_ET"]),
|
||||
('left', ["KEYWORD_PLVS", "KEYWORD_MINVS", "KEYWORD_EST"]),
|
||||
('left', ["SYMBOL_PLUS", "SYMBOL_MINUS"]),
|
||||
('left', ["SYMBOL_TIMES", "SYMBOL_DIVIDE"])
|
||||
]
|
||||
)
|
||||
|
||||
def parse(self, tokens_input) -> ast_nodes.BaseBox:
|
||||
def parse(self, tokens_input) -> ast_nodes.Program:
|
||||
|
||||
# Top-level program stuff
|
||||
@self.pg.production('program : opt_newline module_calls statement_list')
|
||||
def program(tokens):
|
||||
return ast_nodes.Program(tokens[1], tokens[2])
|
||||
# Top-level program stuff
|
||||
@self.pg.production('program : opt_newline module_calls statement_list')
|
||||
def program(tokens):
|
||||
return ast_nodes.Program(tokens[1], tokens[2])
|
||||
|
||||
@self.pg.production('opt_newline : ')
|
||||
@self.pg.production('opt_newline : NEWLINE')
|
||||
def opt_newline(_):
|
||||
return None
|
||||
@self.pg.production('newlines : NEWLINE')
|
||||
@self.pg.production('newlines : NEWLINE newlines')
|
||||
def newlines(_):
|
||||
return None
|
||||
|
||||
# Module calls
|
||||
@self.pg.production('module_calls : ')
|
||||
@self.pg.production('module_calls : module_call NEWLINE module_calls')
|
||||
def module_calls(calls):
|
||||
if len(calls) == 0:
|
||||
return []
|
||||
elif len(calls) == 1:
|
||||
return [calls[0]]
|
||||
else:
|
||||
return [calls[0]] + calls[2]
|
||||
@self.pg.production('opt_newline : ')
|
||||
@self.pg.production('opt_newline : newlines')
|
||||
def opt_newline(_):
|
||||
return None
|
||||
|
||||
@self.pg.production('module_call : KEYWORD_CVM MODULE')
|
||||
def module_call(tokens):
|
||||
return ast_nodes.ModuleCall(tokens[1].value)
|
||||
# Module calls
|
||||
@self.pg.production('module_calls : ')
|
||||
@self.pg.production('module_calls : module_call newlines module_calls')
|
||||
def module_calls(calls):
|
||||
if len(calls) == 0:
|
||||
return []
|
||||
elif len(calls) == 1:
|
||||
return [calls[0]]
|
||||
else:
|
||||
return [calls[0]] + calls[2]
|
||||
|
||||
@self.pg.production('module_call : KEYWORD_CVM MODULE')
|
||||
def module_call(tokens):
|
||||
return ast_nodes.ModuleCall(tokens[1].value)
|
||||
|
||||
|
||||
# Statements
|
||||
@self.pg.production('statements : opt_newline statement_list')
|
||||
def statements(tokens):
|
||||
return tokens[1]
|
||||
# Statements
|
||||
@self.pg.production('statements : opt_newline statement_list')
|
||||
def statements(tokens):
|
||||
return tokens[1]
|
||||
|
||||
@self.pg.production('statement_list : statement opt_newline')
|
||||
@self.pg.production('statement_list : statement NEWLINE statement_list')
|
||||
def statement_list(calls):
|
||||
if len(calls) == 2:
|
||||
return [calls[0]]
|
||||
else:
|
||||
return [calls[0]] + calls[2]
|
||||
@self.pg.production('statement_list : statement opt_newline')
|
||||
@self.pg.production('statement_list : statement newlines statement_list')
|
||||
def statement_list(calls):
|
||||
if len(calls) == 2:
|
||||
return [calls[0]]
|
||||
else:
|
||||
return [calls[0]] + calls[2]
|
||||
|
||||
@self.pg.production('statement : KEYWORD_DESIGNA id KEYWORD_VT expression')
|
||||
def statement_designa(tokens):
|
||||
return ast_nodes.Designa(tokens[1], tokens[3])
|
||||
@self.pg.production('statement : KEYWORD_DESIGNA id KEYWORD_VT expression')
|
||||
def statement_designa(tokens):
|
||||
return ast_nodes.Designa(tokens[1], tokens[3])
|
||||
|
||||
@self.pg.production('statement : expression')
|
||||
def statement_expression(tokens):
|
||||
return ast_nodes.ExpressionStatement(tokens[0])
|
||||
@self.pg.production('statement : expression')
|
||||
def statement_expression(tokens):
|
||||
return ast_nodes.ExpressionStatement(tokens[0])
|
||||
|
||||
@self.pg.production('statement : KEYWORD_DEFINI id ids KEYWORD_VT SYMBOL_LCURL statements SYMBOL_RCURL')
|
||||
def defini(tokens):
|
||||
return ast_nodes.Defini(tokens[1], tokens[2], tokens[5])
|
||||
@self.pg.production('statement : KEYWORD_DEFINI id ids KEYWORD_VT SYMBOL_LCURL statements SYMBOL_RCURL')
|
||||
def defini(tokens):
|
||||
return ast_nodes.Defini(tokens[1], tokens[2], tokens[5])
|
||||
|
||||
@self.pg.production('statement : KEYWORD_REDI expressions')
|
||||
def redi(tokens):
|
||||
return ast_nodes.Redi(tokens[1])
|
||||
@self.pg.production('statement : KEYWORD_REDI expressions')
|
||||
def redi(tokens):
|
||||
return ast_nodes.Redi(tokens[1])
|
||||
|
||||
@self.pg.production('statement : per_statement')
|
||||
@self.pg.production('statement : dum_statement')
|
||||
@self.pg.production('statement : donicum_statement')
|
||||
@self.pg.production('statement : si_statement')
|
||||
def nested_statements(tokens):
|
||||
return tokens[0]
|
||||
@self.pg.production('statement : per_statement')
|
||||
@self.pg.production('statement : dum_statement')
|
||||
@self.pg.production('statement : donicum_statement')
|
||||
@self.pg.production('statement : si_statement')
|
||||
def nested_statements(tokens):
|
||||
return tokens[0]
|
||||
|
||||
@self.pg.production('statement : KEYWORD_ERVMPE')
|
||||
def erumpe(_):
|
||||
return ast_nodes.Erumpe()
|
||||
@self.pg.production('statement : KEYWORD_ERVMPE')
|
||||
def erumpe(_):
|
||||
return ast_nodes.Erumpe()
|
||||
|
||||
@self.pg.production('si_statement : KEYWORD_SI expression KEYWORD_TVNC SYMBOL_LCURL statements SYMBOL_RCURL')
|
||||
@self.pg.production('si_statement : KEYWORD_SI expression KEYWORD_TVNC SYMBOL_LCURL statements SYMBOL_RCURL aluid_statement')
|
||||
def si_statement(tokens):
|
||||
if len(tokens) == 7:
|
||||
return ast_nodes.SiStatement(tokens[1], tokens[4], tokens[6])
|
||||
else:
|
||||
return ast_nodes.SiStatement(tokens[1], tokens[4], None)
|
||||
@self.pg.production('si_statement : KEYWORD_SI expression KEYWORD_TVNC SYMBOL_LCURL statements SYMBOL_RCURL')
|
||||
@self.pg.production('si_statement : KEYWORD_SI expression KEYWORD_TVNC SYMBOL_LCURL statements SYMBOL_RCURL aluid_statement')
|
||||
def si_statement(tokens):
|
||||
if len(tokens) == 7:
|
||||
return ast_nodes.SiStatement(tokens[1], tokens[4], tokens[6])
|
||||
else:
|
||||
return ast_nodes.SiStatement(tokens[1], tokens[4], None)
|
||||
|
||||
@self.pg.production('aluid_statement : KEYWORD_ALVID si_statement')
|
||||
def aluid_si(tokens):
|
||||
return [tokens[1]]
|
||||
@self.pg.production('aluid_statement : KEYWORD_ALVID si_statement')
|
||||
def aluid_si(tokens):
|
||||
return [tokens[1]]
|
||||
|
||||
@self.pg.production('aluid_statement : KEYWORD_ALVID SYMBOL_LCURL statements SYMBOL_RCURL')
|
||||
def aluid(tokens):
|
||||
return tokens[2]
|
||||
@self.pg.production('aluid_statement : KEYWORD_ALVID SYMBOL_LCURL statements SYMBOL_RCURL')
|
||||
def aluid(tokens):
|
||||
return tokens[2]
|
||||
|
||||
@self.pg.production('dum_statement : KEYWORD_DVM expression KEYWORD_FACE SYMBOL_LCURL statements SYMBOL_RCURL')
|
||||
def dum(tokens):
|
||||
return ast_nodes.DumStatement(tokens[1], tokens[4])
|
||||
@self.pg.production('dum_statement : KEYWORD_DVM expression KEYWORD_FACE SYMBOL_LCURL statements SYMBOL_RCURL')
|
||||
def dum(tokens):
|
||||
return ast_nodes.DumStatement(tokens[1], tokens[4])
|
||||
|
||||
@self.pg.production('per_statement : KEYWORD_PER id KEYWORD_IN expression KEYWORD_FACE SYMBOL_LCURL statements SYMBOL_RCURL')
|
||||
def per(tokens):
|
||||
return ast_nodes.PerStatement(tokens[3], tokens[1], tokens[6])
|
||||
@self.pg.production('per_statement : KEYWORD_PER id KEYWORD_IN expression KEYWORD_FACE SYMBOL_LCURL statements SYMBOL_RCURL')
|
||||
def per(tokens):
|
||||
return ast_nodes.PerStatement(tokens[3], tokens[1], tokens[6])
|
||||
|
||||
@self.pg.production('donicum_statement : KEYWORD_DONICVM id KEYWORD_VT expression KEYWORD_VSQVE expression KEYWORD_FACE SYMBOL_LCURL statements SYMBOL_RCURL')
|
||||
def donicum(tokens):
|
||||
range_array = ast_nodes.DataRangeArray(tokens[3], tokens[5])
|
||||
return ast_nodes.PerStatement(range_array, tokens[1], tokens[8])
|
||||
@self.pg.production('donicum_statement : KEYWORD_DONICVM id KEYWORD_VT expression KEYWORD_VSQVE expression KEYWORD_FACE SYMBOL_LCURL statements SYMBOL_RCURL')
|
||||
def donicum(tokens):
|
||||
range_array = ast_nodes.DataRangeArray(tokens[3], tokens[5])
|
||||
return ast_nodes.PerStatement(range_array, tokens[1], tokens[8])
|
||||
|
||||
# expressions
|
||||
@self.pg.production('expressions : SYMBOL_LPARENS expression_list')
|
||||
def expressions(tokens):
|
||||
return tokens[1]
|
||||
# expressions
|
||||
@self.pg.production('expressions : SYMBOL_LPARENS expression_list')
|
||||
def expressions(tokens):
|
||||
return tokens[1]
|
||||
|
||||
@self.pg.production('expression_list : SYMBOL_RPARENS')
|
||||
@self.pg.production('expression_list : expression SYMBOL_RPARENS')
|
||||
@self.pg.production('expression_list : expression SYMBOL_COMMA expression_list')
|
||||
def expression_list(calls):
|
||||
if len(calls) == 1:
|
||||
return []
|
||||
elif len(calls) == 2:
|
||||
return [calls[0]]
|
||||
else:
|
||||
return [calls[0]] + calls[2]
|
||||
@self.pg.production('expression_list : SYMBOL_RPARENS')
|
||||
@self.pg.production('expression_list : expression SYMBOL_RPARENS')
|
||||
@self.pg.production('expression_list : expression SYMBOL_COMMA expression_list')
|
||||
def expression_list(calls):
|
||||
if len(calls) == 1:
|
||||
return []
|
||||
elif len(calls) == 2:
|
||||
return [calls[0]]
|
||||
else:
|
||||
return [calls[0]] + calls[2]
|
||||
|
||||
@self.pg.production('expression : id')
|
||||
def expression_id(tokens):
|
||||
return tokens[0]
|
||||
@self.pg.production('expression : id')
|
||||
def expression_id(tokens):
|
||||
return tokens[0]
|
||||
|
||||
@self.pg.production('expression : BUILTIN expressions')
|
||||
def expression_builtin(tokens):
|
||||
return ast_nodes.BuiltIn(tokens[0].value, tokens[1])
|
||||
@self.pg.production('expression : BUILTIN expressions')
|
||||
def expression_builtin(tokens):
|
||||
return ast_nodes.BuiltIn(tokens[0].value, tokens[1])
|
||||
|
||||
@self.pg.production('expression : DATA_STRING')
|
||||
def expression_string(tokens):
|
||||
return ast_nodes.String(tokens[0].value[1:-1])
|
||||
@self.pg.production('expression : DATA_STRING')
|
||||
def expression_string(tokens):
|
||||
return ast_nodes.String(tokens[0].value[1:-1])
|
||||
|
||||
@self.pg.production('expression : DATA_NUMERAL')
|
||||
def expression_numeral(tokens):
|
||||
return ast_nodes.Numeral(tokens[0].value)
|
||||
@self.pg.production('expression : DATA_NUMERAL')
|
||||
def expression_numeral(tokens):
|
||||
return ast_nodes.Numeral(tokens[0].value)
|
||||
|
||||
@self.pg.production('expression : KEYWORD_FALSITAS')
|
||||
@self.pg.production('expression : KEYWORD_VERITAS')
|
||||
def expression_bool(tokens):
|
||||
return ast_nodes.Bool(tokens[0].name == "KEYWORD_VERITAS")
|
||||
@self.pg.production('expression : KEYWORD_FALSITAS')
|
||||
@self.pg.production('expression : KEYWORD_VERITAS')
|
||||
def expression_bool(tokens):
|
||||
return ast_nodes.Bool(tokens[0].name == "KEYWORD_VERITAS")
|
||||
|
||||
@self.pg.production('expression : KEYWORD_NVLLVS')
|
||||
def expression_nullus(_):
|
||||
return ast_nodes.Nullus()
|
||||
@self.pg.production('expression : KEYWORD_NVLLVS')
|
||||
def expression_nullus(_):
|
||||
return ast_nodes.Nullus()
|
||||
|
||||
@self.pg.production('expression : expression SYMBOL_MINUS expression')
|
||||
@self.pg.production('expression : expression SYMBOL_PLUS expression')
|
||||
@self.pg.production('expression : expression SYMBOL_TIMES expression')
|
||||
@self.pg.production('expression : expression SYMBOL_DIVIDE expression')
|
||||
@self.pg.production('expression : expression KEYWORD_EST expression')
|
||||
@self.pg.production('expression : expression KEYWORD_MINVS expression')
|
||||
@self.pg.production('expression : expression KEYWORD_PLVS expression')
|
||||
def binop(tokens):
|
||||
return ast_nodes.BinOp(tokens[0], tokens[2], tokens[1].name)
|
||||
@self.pg.production('expression : expression SYMBOL_MINUS expression')
|
||||
@self.pg.production('expression : expression SYMBOL_PLUS expression')
|
||||
@self.pg.production('expression : expression SYMBOL_TIMES expression')
|
||||
@self.pg.production('expression : expression SYMBOL_DIVIDE expression')
|
||||
@self.pg.production('expression : expression KEYWORD_EST expression')
|
||||
@self.pg.production('expression : expression KEYWORD_MINVS expression')
|
||||
@self.pg.production('expression : expression KEYWORD_PLVS expression')
|
||||
@self.pg.production('expression : expression KEYWORD_ET expression')
|
||||
@self.pg.production('expression : expression KEYWORD_AVT expression')
|
||||
def binop(tokens):
|
||||
return ast_nodes.BinOp(tokens[0], tokens[2], tokens[1].name)
|
||||
|
||||
@self.pg.production('expression : KEYWORD_INVOCA id expressions')
|
||||
def invoca(tokens):
|
||||
return ast_nodes.Invoca(tokens[1], tokens[2])
|
||||
@self.pg.production('expression : KEYWORD_INVOCA id expressions')
|
||||
def invoca(tokens):
|
||||
return ast_nodes.Invoca(tokens[1], tokens[2])
|
||||
|
||||
@self.pg.production('expression : SYMBOL_LPARENS expression SYMBOL_RPARENS')
|
||||
def parens(tokens):
|
||||
return tokens[1]
|
||||
@self.pg.production('expression : SYMBOL_LPARENS expression SYMBOL_RPARENS')
|
||||
def parens(tokens):
|
||||
return tokens[1]
|
||||
|
||||
@self.pg.production('expression : SYMBOL_LBRACKET expressions SYMBOL_RBRACKET')
|
||||
def array(tokens):
|
||||
return ast_nodes.DataArray(tokens[1])
|
||||
@self.pg.production('expression : SYMBOL_LBRACKET expressions SYMBOL_RBRACKET')
|
||||
def array(tokens):
|
||||
return ast_nodes.DataArray(tokens[1])
|
||||
|
||||
@self.pg.production('expression : SYMBOL_LBRACKET expression KEYWORD_VSQVE expression SYMBOL_RBRACKET')
|
||||
def range_array(tokens):
|
||||
return ast_nodes.DataRangeArray(tokens[1], tokens[3])
|
||||
@self.pg.production('expression : SYMBOL_LBRACKET expression KEYWORD_VSQVE expression SYMBOL_RBRACKET')
|
||||
def range_array(tokens):
|
||||
return ast_nodes.DataRangeArray(tokens[1], tokens[3])
|
||||
|
||||
# ids
|
||||
@self.pg.production('ids : SYMBOL_LPARENS id_list')
|
||||
def ids(tokens):
|
||||
return tokens[1]
|
||||
# ids
|
||||
@self.pg.production('ids : SYMBOL_LPARENS id_list')
|
||||
def ids(tokens):
|
||||
return tokens[1]
|
||||
|
||||
@self.pg.production('id_list : SYMBOL_RPARENS')
|
||||
@self.pg.production('id_list : id SYMBOL_RPARENS')
|
||||
@self.pg.production('id_list : id SYMBOL_COMMA id_list')
|
||||
def id_list(calls):
|
||||
if len(calls) == 1:
|
||||
return []
|
||||
elif len(calls) == 2:
|
||||
return [calls[0]]
|
||||
else:
|
||||
return [calls[0]] + calls[2]
|
||||
@self.pg.production('id_list : SYMBOL_RPARENS')
|
||||
@self.pg.production('id_list : id SYMBOL_RPARENS')
|
||||
@self.pg.production('id_list : id SYMBOL_COMMA id_list')
|
||||
def id_list(calls):
|
||||
if len(calls) == 1:
|
||||
return []
|
||||
elif len(calls) == 2:
|
||||
return [calls[0]]
|
||||
else:
|
||||
return [calls[0]] + calls[2]
|
||||
|
||||
@self.pg.production("id : ID")
|
||||
def id_expression(tokens):
|
||||
return ast_nodes.ID(tokens[0].value)
|
||||
@self.pg.production("id : ID")
|
||||
def id_expression(tokens):
|
||||
return ast_nodes.ID(tokens[0].value)
|
||||
|
||||
@self.pg.error
|
||||
def error_handle(token):
|
||||
raise Exception(token.name, token.value, token.source_pos)
|
||||
@self.pg.error
|
||||
def error_handle(token):
|
||||
raise SyntaxError(token.name, token.value, token.source_pos)
|
||||
|
||||
parser = self.pg.build()
|
||||
return parser.parse(tokens_input)
|
||||
parser = self.pg.build()
|
||||
return parser.parse(tokens_input) # type: ignore
|
||||
|
||||
87
centvrion/values.py
Normal file
87
centvrion/values.py
Normal file
@@ -0,0 +1,87 @@
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
class Val(ABC):
|
||||
@abstractmethod
|
||||
def value(self): ...
|
||||
|
||||
def __repr__(self):
|
||||
return f"{self.__class__.__name__}({self.value()!r})"
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, type(self)) and self.value() == other.value()
|
||||
|
||||
class ValInt(Val):
|
||||
def __init__(self, v: int):
|
||||
assert isinstance(v, int) and not isinstance(v, bool)
|
||||
self._v = v
|
||||
|
||||
def value(self):
|
||||
return self._v
|
||||
|
||||
def __bool__(self):
|
||||
return self._v != 0
|
||||
|
||||
def __lt__(self, other):
|
||||
return self._v < other.value()
|
||||
|
||||
def __gt__(self, other):
|
||||
return self._v > other.value()
|
||||
|
||||
class ValStr(Val):
|
||||
def __init__(self, v: str):
|
||||
assert isinstance(v, str)
|
||||
self._v = v
|
||||
|
||||
def value(self):
|
||||
return self._v
|
||||
|
||||
def __bool__(self):
|
||||
return self._v != ""
|
||||
|
||||
class ValBool(Val):
|
||||
def __init__(self, v: bool):
|
||||
assert isinstance(v, bool)
|
||||
self._v = v
|
||||
|
||||
def value(self):
|
||||
return self._v
|
||||
|
||||
def __bool__(self):
|
||||
return self._v
|
||||
|
||||
class ValList(Val):
|
||||
def __init__(self, v: list):
|
||||
assert isinstance(v, list)
|
||||
self._v = v
|
||||
|
||||
def value(self):
|
||||
return self._v
|
||||
|
||||
def __bool__(self):
|
||||
return len(self._v) > 0
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self._v)
|
||||
|
||||
class ValNul(Val):
|
||||
def value(self):
|
||||
return None
|
||||
|
||||
def __bool__(self):
|
||||
raise TypeError("NVLLVS cannot be evaluated as a boolean")
|
||||
|
||||
class ValFunc(Val):
|
||||
def __init__(self, params: list, body: list):
|
||||
self._params = params
|
||||
self._body = body
|
||||
|
||||
def value(self):
|
||||
return (self._params, self._body)
|
||||
|
||||
@property
|
||||
def params(self):
|
||||
return self._params
|
||||
|
||||
@property
|
||||
def body(self):
|
||||
return self._body
|
||||
@@ -4,14 +4,14 @@ DESIGNA correct VT FORTIS_NVMERVS(I,C)
|
||||
DESIGNA gvess VT NVLLVS
|
||||
|
||||
DVM FALSITAS FACE {
|
||||
DESIGNA gvess VT AVDI_NVMERVS()
|
||||
SI gvess MINVS correct TVNC {
|
||||
DICE("Too low!")
|
||||
} ALVID SI gvess PLVS correct TVNC {
|
||||
DICE("Too high!")
|
||||
} ALVID {
|
||||
ERVMPE
|
||||
}
|
||||
DESIGNA gvess VT AVDI_NVMERVS()
|
||||
SI gvess MINVS correct TVNC {
|
||||
DICE("Too low!")
|
||||
} ALVID SI gvess PLVS correct TVNC {
|
||||
DICE("Too high!")
|
||||
} ALVID {
|
||||
ERVMPE
|
||||
}
|
||||
}
|
||||
|
||||
DICE("You guessed correctly!")
|
||||
@@ -1,2 +0,0 @@
|
||||
\relax
|
||||
\gdef \@abspage@last{2}
|
||||
@@ -1,30 +0,0 @@
|
||||
# Fdb version 3
|
||||
["xdvipdfmx"] 1666044971 "main.xdv" "main.pdf" "main" 1666044971
|
||||
"main.xdv" 1666044971 18856 0aa2d80a726d535daf28e1e7b8969553 "xelatex"
|
||||
(generated)
|
||||
"main.pdf"
|
||||
["xelatex"] 1666044971 "/home/nikolaj/Code/python/centvrion/language/main.tex" "main.xdv" "main" 1666044971
|
||||
"/home/nikolaj/Code/python/centvrion/language/main.tex" 1666044970 4376 88792a4bab5d145c10208dea722cbecb ""
|
||||
"/usr/share/texmf-dist/tex/generic/iftex/iftex.sty" 1650183167 7237 bdd120a32c8fdb4b433cf9ca2e7cd98a ""
|
||||
"/usr/share/texmf-dist/tex/generic/iftex/ifvtex.sty" 1650183167 1057 525c2192b5febbd8c1f662c9468335bb ""
|
||||
"/usr/share/texmf-dist/tex/latex/base/article.cls" 1650183167 20144 8a7de377ae7a11ee924a7499611f5a9d ""
|
||||
"/usr/share/texmf-dist/tex/latex/base/fontenc.sty" 1650183167 4946 461cc78f6f26901410d9f1d725079cc6 ""
|
||||
"/usr/share/texmf-dist/tex/latex/base/size10.clo" 1650183167 8448 96f18c76bf608a36ee6fbf021ac1dd32 ""
|
||||
"/usr/share/texmf-dist/tex/latex/base/ts1cmr.fd" 1650183167 2430 06a89bcded389391906798ea7a3f3aaa ""
|
||||
"/usr/share/texmf-dist/tex/latex/base/tuenc.def" 1650183167 29098 3e2b8f2cbae539bde3ed8f63503c0954 ""
|
||||
"/usr/share/texmf-dist/tex/latex/fontspec/fontspec-xetex.sty" 1650183167 162076 2f6d31c4632f2730c57b9c0fda038e15 ""
|
||||
"/usr/share/texmf-dist/tex/latex/fontspec/fontspec.cfg" 1650183167 549 c4adac819276241fea8eb79c5ab7b99e ""
|
||||
"/usr/share/texmf-dist/tex/latex/fontspec/fontspec.sty" 1650183167 1656 7e824878bad4df5a3e8bba4e463d9126 ""
|
||||
"/usr/share/texmf-dist/tex/latex/geometry/geometry.sty" 1650183167 41601 9cf6c5257b1bc7af01a58859749dd37a ""
|
||||
"/usr/share/texmf-dist/tex/latex/graphics/keyval.sty" 1650183167 2671 4de6781a30211fe0ea4c672e4a2a8166 ""
|
||||
"/usr/share/texmf-dist/tex/latex/l3backend/l3backend-xetex.def" 1650183167 35763 558b6bb076dfa9b058fe5c58dc6e0434 ""
|
||||
"/usr/share/texmf-dist/tex/latex/l3kernel/expl3.sty" 1650183167 6107 e4124ef96db512db87780f95c2a6b136 ""
|
||||
"/usr/share/texmf-dist/tex/latex/l3packages/xparse/xparse.sty" 1650183167 6758 7d9d899cbbfc962fbc4bb93f4c69eec2 ""
|
||||
"/usr/share/texmf-dist/web2c/texmf.cnf" 1650183167 39911 2da6c67557ec033436fe5418a70a8a61 ""
|
||||
"/var/lib/texmf/web2c/xetex/xelatex.fmt" 1656162080 5825168 1cdc03dd54937efcb6a623296105d1a8 ""
|
||||
"main.aux" 1666044971 32 044b7f8fc9779af7531264e0c5c84b6d "xelatex"
|
||||
"main.tex" 1666044970 4376 88792a4bab5d145c10208dea722cbecb ""
|
||||
(generated)
|
||||
"main.aux"
|
||||
"main.log"
|
||||
"main.xdv"
|
||||
@@ -1,146 +0,0 @@
|
||||
PWD /home/nikolaj/Code/python/centvrion/language
|
||||
INPUT /usr/share/texmf-dist/web2c/texmf.cnf
|
||||
INPUT /var/lib/texmf/web2c/xetex/xelatex.fmt
|
||||
INPUT /home/nikolaj/Code/python/centvrion/language/main.tex
|
||||
OUTPUT main.log
|
||||
INPUT /usr/share/texmf-dist/tex/latex/base/article.cls
|
||||
INPUT /usr/share/texmf-dist/tex/latex/base/article.cls
|
||||
INPUT /usr/share/texmf-dist/tex/latex/base/article.cls
|
||||
INPUT /usr/share/texmf-dist/tex/latex/base/article.cls
|
||||
INPUT /usr/share/texmf-dist/tex/latex/base/article.cls
|
||||
INPUT /usr/share/texmf-dist/tex/latex/base/article.cls
|
||||
INPUT /usr/share/texmf-dist/tex/latex/base/article.cls
|
||||
INPUT /usr/share/texmf-dist/tex/latex/base/article.cls
|
||||
INPUT /usr/share/texmf-dist/tex/latex/base/article.cls
|
||||
INPUT /usr/share/texmf-dist/tex/latex/base/article.cls
|
||||
INPUT /usr/share/texmf-dist/tex/latex/base/article.cls
|
||||
INPUT /usr/share/texmf-dist/tex/latex/base/size10.clo
|
||||
INPUT /usr/share/texmf-dist/tex/latex/base/size10.clo
|
||||
INPUT /usr/share/texmf-dist/tex/latex/base/size10.clo
|
||||
INPUT /usr/share/texmf-dist/tex/latex/base/size10.clo
|
||||
INPUT /usr/share/texmf-dist/tex/latex/geometry/geometry.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/geometry/geometry.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/geometry/geometry.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/geometry/geometry.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/geometry/geometry.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/geometry/geometry.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/geometry/geometry.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/geometry/geometry.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/geometry/geometry.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/geometry/geometry.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/geometry/geometry.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/graphics/keyval.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/graphics/keyval.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/graphics/keyval.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/graphics/keyval.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/graphics/keyval.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/graphics/keyval.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/graphics/keyval.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/graphics/keyval.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/graphics/keyval.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/graphics/keyval.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/graphics/keyval.sty
|
||||
INPUT /usr/share/texmf-dist/tex/generic/iftex/ifvtex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/generic/iftex/ifvtex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/generic/iftex/ifvtex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/generic/iftex/ifvtex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/generic/iftex/ifvtex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/generic/iftex/ifvtex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/generic/iftex/ifvtex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/generic/iftex/ifvtex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/generic/iftex/ifvtex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/generic/iftex/ifvtex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/generic/iftex/ifvtex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/generic/iftex/iftex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/generic/iftex/iftex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/generic/iftex/iftex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/generic/iftex/iftex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/generic/iftex/iftex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/generic/iftex/iftex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/generic/iftex/iftex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/generic/iftex/iftex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/generic/iftex/iftex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/generic/iftex/iftex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/generic/iftex/iftex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3packages/xparse/xparse.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3packages/xparse/xparse.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3packages/xparse/xparse.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3packages/xparse/xparse.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3packages/xparse/xparse.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3packages/xparse/xparse.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3packages/xparse/xparse.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3packages/xparse/xparse.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3packages/xparse/xparse.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3packages/xparse/xparse.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3packages/xparse/xparse.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3kernel/expl3.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3kernel/expl3.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3kernel/expl3.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3kernel/expl3.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3kernel/expl3.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3kernel/expl3.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3kernel/expl3.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3kernel/expl3.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3kernel/expl3.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3kernel/expl3.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3kernel/expl3.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3backend/l3backend-xetex.def
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3backend/l3backend-xetex.def
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3backend/l3backend-xetex.def
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3backend/l3backend-xetex.def
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3backend/l3backend-xetex.def
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3backend/l3backend-xetex.def
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3backend/l3backend-xetex.def
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3backend/l3backend-xetex.def
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3backend/l3backend-xetex.def
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3backend/l3backend-xetex.def
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3backend/l3backend-xetex.def
|
||||
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec-xetex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec-xetex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec-xetex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec-xetex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec-xetex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec-xetex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec-xetex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec-xetex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec-xetex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec-xetex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec-xetex.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/l3packages/xparse/xparse.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/base/tuenc.def
|
||||
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
|
||||
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec.cfg
|
||||
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec.cfg
|
||||
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec.cfg
|
||||
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec.cfg
|
||||
INPUT ./main.aux
|
||||
INPUT main.aux
|
||||
INPUT main.aux
|
||||
OUTPUT main.aux
|
||||
INPUT /usr/share/texmf-dist/tex/latex/base/ts1cmr.fd
|
||||
INPUT /usr/share/texmf-dist/tex/latex/base/ts1cmr.fd
|
||||
INPUT /usr/share/texmf-dist/tex/latex/base/ts1cmr.fd
|
||||
INPUT /usr/share/texmf-dist/tex/latex/base/ts1cmr.fd
|
||||
OUTPUT main.xdv
|
||||
INPUT main.aux
|
||||
@@ -1,251 +0,0 @@
|
||||
This is XeTeX, Version 3.141592653-2.6-0.999994 (TeX Live 2022/Arch Linux) (preloaded format=xelatex 2022.6.25) 18 OCT 2022 00:16
|
||||
entering extended mode
|
||||
restricted \write18 enabled.
|
||||
file:line:error style messages enabled.
|
||||
%&-line parsing enabled.
|
||||
**/home/nikolaj/Code/python/centvrion/language/main.tex
|
||||
(/home/nikolaj/Code/python/centvrion/language/main.tex
|
||||
LaTeX2e <2021-11-15> patch level 1
|
||||
L3 programming layer <2022-04-10> (/usr/share/texmf-dist/tex/latex/base/article.cls
|
||||
Document Class: article 2021/10/04 v1.4n Standard LaTeX document class
|
||||
(/usr/share/texmf-dist/tex/latex/base/size10.clo
|
||||
File: size10.clo 2021/10/04 v1.4n Standard LaTeX file (size option)
|
||||
)
|
||||
\c@part=\count181
|
||||
\c@section=\count182
|
||||
\c@subsection=\count183
|
||||
\c@subsubsection=\count184
|
||||
\c@paragraph=\count185
|
||||
\c@subparagraph=\count186
|
||||
\c@figure=\count187
|
||||
\c@table=\count188
|
||||
\abovecaptionskip=\skip47
|
||||
\belowcaptionskip=\skip48
|
||||
\bibindent=\dimen138
|
||||
) (/usr/share/texmf-dist/tex/latex/geometry/geometry.sty
|
||||
Package: geometry 2020/01/02 v5.9 Page Geometry
|
||||
(/usr/share/texmf-dist/tex/latex/graphics/keyval.sty
|
||||
Package: keyval 2014/10/28 v1.15 key=value parser (DPC)
|
||||
\KV@toks@=\toks16
|
||||
) (/usr/share/texmf-dist/tex/generic/iftex/ifvtex.sty
|
||||
Package: ifvtex 2019/10/25 v1.7 ifvtex legacy package. Use iftex instead.
|
||||
(/usr/share/texmf-dist/tex/generic/iftex/iftex.sty
|
||||
Package: iftex 2022/02/03 v1.0f TeX engine tests
|
||||
))
|
||||
\Gm@cnth=\count189
|
||||
\Gm@cntv=\count190
|
||||
\c@Gm@tempcnt=\count191
|
||||
\Gm@bindingoffset=\dimen139
|
||||
\Gm@wd@mp=\dimen140
|
||||
\Gm@odd@mp=\dimen141
|
||||
\Gm@even@mp=\dimen142
|
||||
\Gm@layoutwidth=\dimen143
|
||||
\Gm@layoutheight=\dimen144
|
||||
\Gm@layouthoffset=\dimen145
|
||||
\Gm@layoutvoffset=\dimen146
|
||||
\Gm@dimlist=\toks17
|
||||
) (/usr/share/texmf-dist/tex/latex/fontspec/fontspec.sty (/usr/share/texmf-dist/tex/latex/l3packages/xparse/xparse.sty (/usr/share/texmf-dist/tex/latex/l3kernel/expl3.sty
|
||||
Package: expl3 2022-04-10 L3 programming layer (loader)
|
||||
(/usr/share/texmf-dist/tex/latex/l3backend/l3backend-xetex.def
|
||||
File: l3backend-xetex.def 2022-04-14 L3 backend support: XeTeX
|
||||
\l__color_backend_stack_int=\count192
|
||||
\g__color_backend_stack_int=\count193
|
||||
\g__graphics_track_int=\count194
|
||||
\l__pdf_internal_box=\box50
|
||||
\g__pdf_backend_object_int=\count195
|
||||
\g__pdf_backend_annotation_int=\count196
|
||||
\g__pdf_backend_link_int=\count197
|
||||
))
|
||||
Package: xparse 2022-01-12 L3 Experimental document command parser
|
||||
)
|
||||
Package: fontspec 2022/01/15 v2.8a Font selection for XeLaTeX and LuaLaTeX
|
||||
(/usr/share/texmf-dist/tex/latex/fontspec/fontspec-xetex.sty
|
||||
Package: fontspec-xetex 2022/01/15 v2.8a Font selection for XeLaTeX and LuaLaTeX
|
||||
\l__fontspec_script_int=\count198
|
||||
\l__fontspec_language_int=\count199
|
||||
\l__fontspec_strnum_int=\count266
|
||||
\l__fontspec_tmp_int=\count267
|
||||
\l__fontspec_tmpa_int=\count268
|
||||
\l__fontspec_tmpb_int=\count269
|
||||
\l__fontspec_tmpc_int=\count270
|
||||
\l__fontspec_em_int=\count271
|
||||
\l__fontspec_emdef_int=\count272
|
||||
\l__fontspec_strong_int=\count273
|
||||
\l__fontspec_strongdef_int=\count274
|
||||
\l__fontspec_tmpa_dim=\dimen147
|
||||
\l__fontspec_tmpb_dim=\dimen148
|
||||
\l__fontspec_tmpc_dim=\dimen149
|
||||
(/usr/share/texmf-dist/tex/latex/base/fontenc.sty
|
||||
Package: fontenc 2021/04/29 v2.0v Standard LaTeX package
|
||||
) (/usr/share/texmf-dist/tex/latex/fontspec/fontspec.cfg)))
|
||||
|
||||
Package fontspec Info: Could not resolve font "Hurmit Nerd Font Mono/I" (it
|
||||
(fontspec) probably doesn't exist).
|
||||
|
||||
|
||||
Package fontspec Info: Font family 'HurmitNerdFontMono(0)' created for font
|
||||
(fontspec) 'Hurmit Nerd Font Mono' with options
|
||||
(fontspec) [WordSpace={1,0,0},HyphenChar=None,PunctuationSpace=WordSpace,Scale=0.7].
|
||||
(fontspec)
|
||||
(fontspec) This font family consists of the following NFSS
|
||||
(fontspec) series/shapes:
|
||||
(fontspec)
|
||||
(fontspec) - 'normal' (m/n) with NFSS spec.: <->s*[0.7]"Hurmit
|
||||
(fontspec) Nerd Font Mono/OT:language=dflt;"
|
||||
(fontspec) - 'small caps' (m/sc) with NFSS spec.:
|
||||
(fontspec) and font adjustment code:
|
||||
(fontspec) \fontdimen 2\font =1\fontdimen 2\font \fontdimen 3\font
|
||||
(fontspec) =0\fontdimen 3\font \fontdimen 4\font =0\fontdimen
|
||||
(fontspec) 4\font \fontdimen 7\font =0\fontdimen 2\font
|
||||
(fontspec) \tex_hyphenchar:D \font =-1\scan_stop:
|
||||
(fontspec) - 'bold' (b/n) with NFSS spec.: <->s*[0.7]"Hurmit Nerd
|
||||
(fontspec) Font Mono/B/OT:language=dflt;"
|
||||
(fontspec) - 'bold small caps' (b/sc) with NFSS spec.:
|
||||
(fontspec) and font adjustment code:
|
||||
(fontspec) \fontdimen 2\font =1\fontdimen 2\font \fontdimen 3\font
|
||||
(fontspec) =0\fontdimen 3\font \fontdimen 4\font =0\fontdimen
|
||||
(fontspec) 4\font \fontdimen 7\font =0\fontdimen 2\font
|
||||
(fontspec) \tex_hyphenchar:D \font =-1\scan_stop:
|
||||
(fontspec) - 'bold italic' (b/it) with NFSS spec.:
|
||||
(fontspec) <->s*[0.7]"Hurmit Nerd Font Mono/BI/OT:language=dflt;"
|
||||
(fontspec) - 'bold italic small caps' (b/scit) with NFSS spec.:
|
||||
(fontspec) and font adjustment code:
|
||||
(fontspec) \fontdimen 2\font =1\fontdimen 2\font \fontdimen 3\font
|
||||
(fontspec) =0\fontdimen 3\font \fontdimen 4\font =0\fontdimen
|
||||
(fontspec) 4\font \fontdimen 7\font =0\fontdimen 2\font
|
||||
(fontspec) \tex_hyphenchar:D \font =-1\scan_stop:
|
||||
|
||||
(./main.aux)
|
||||
\openout1 = `main.aux'.
|
||||
|
||||
LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 11.
|
||||
LaTeX Font Info: ... okay on input line 11.
|
||||
LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 11.
|
||||
LaTeX Font Info: ... okay on input line 11.
|
||||
LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 11.
|
||||
LaTeX Font Info: ... okay on input line 11.
|
||||
LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 11.
|
||||
LaTeX Font Info: ... okay on input line 11.
|
||||
LaTeX Font Info: Checking defaults for TS1/cmr/m/n on input line 11.
|
||||
LaTeX Font Info: Trying to load font information for TS1+cmr on input line 11.
|
||||
(/usr/share/texmf-dist/tex/latex/base/ts1cmr.fd
|
||||
File: ts1cmr.fd 2019/12/16 v2.5j Standard LaTeX font definitions
|
||||
)
|
||||
LaTeX Font Info: ... okay on input line 11.
|
||||
LaTeX Font Info: Checking defaults for TU/lmr/m/n on input line 11.
|
||||
LaTeX Font Info: ... okay on input line 11.
|
||||
LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 11.
|
||||
LaTeX Font Info: ... okay on input line 11.
|
||||
LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 11.
|
||||
LaTeX Font Info: ... okay on input line 11.
|
||||
|
||||
*geometry* driver: auto-detecting
|
||||
*geometry* detected driver: xetex
|
||||
*geometry* verbose mode - [ preamble ] result:
|
||||
* driver: xetex
|
||||
* paper: a4paper
|
||||
* layout: <same size as paper>
|
||||
* layoutoffset:(h,v)=(0.0pt,0.0pt)
|
||||
* modes:
|
||||
* h-part:(L,W,R)=(72.26999pt, 452.9679pt, 72.26999pt)
|
||||
* v-part:(T,H,B)=(72.26999pt, 700.50687pt, 72.26999pt)
|
||||
* \paperwidth=597.50787pt
|
||||
* \paperheight=845.04684pt
|
||||
* \textwidth=452.9679pt
|
||||
* \textheight=700.50687pt
|
||||
* \oddsidemargin=0.0pt
|
||||
* \evensidemargin=0.0pt
|
||||
* \topmargin=-37.0pt
|
||||
* \headheight=12.0pt
|
||||
* \headsep=25.0pt
|
||||
* \topskip=10.0pt
|
||||
* \footskip=30.0pt
|
||||
* \marginparwidth=57.0pt
|
||||
* \marginparsep=11.0pt
|
||||
* \columnsep=10.0pt
|
||||
* \skip\footins=9.0pt plus 4.0pt minus 2.0pt
|
||||
* \hoffset=0.0pt
|
||||
* \voffset=0.0pt
|
||||
* \mag=1000
|
||||
* \@twocolumnfalse
|
||||
* \@twosidefalse
|
||||
* \@mparswitchfalse
|
||||
* \@reversemarginfalse
|
||||
* (1in=72.27pt=25.4mm, 1cm=28.453pt)
|
||||
|
||||
|
||||
Package fontspec Info: Adjusting the maths setup (use [no-math] to avoid
|
||||
(fontspec) this).
|
||||
|
||||
\symlegacymaths=\mathgroup4
|
||||
LaTeX Font Info: Overwriting symbol font `legacymaths' in version `bold'
|
||||
(Font) OT1/cmr/m/n --> OT1/cmr/bx/n on input line 11.
|
||||
LaTeX Font Info: Redeclaring math accent \acute on input line 11.
|
||||
LaTeX Font Info: Redeclaring math accent \grave on input line 11.
|
||||
LaTeX Font Info: Redeclaring math accent \ddot on input line 11.
|
||||
LaTeX Font Info: Redeclaring math accent \tilde on input line 11.
|
||||
LaTeX Font Info: Redeclaring math accent \bar on input line 11.
|
||||
LaTeX Font Info: Redeclaring math accent \breve on input line 11.
|
||||
LaTeX Font Info: Redeclaring math accent \check on input line 11.
|
||||
LaTeX Font Info: Redeclaring math accent \hat on input line 11.
|
||||
LaTeX Font Info: Redeclaring math accent \dot on input line 11.
|
||||
LaTeX Font Info: Redeclaring math accent \mathring on input line 11.
|
||||
LaTeX Font Info: Redeclaring math symbol \colon on input line 11.
|
||||
LaTeX Font Info: Redeclaring math symbol \Gamma on input line 11.
|
||||
LaTeX Font Info: Redeclaring math symbol \Delta on input line 11.
|
||||
LaTeX Font Info: Redeclaring math symbol \Theta on input line 11.
|
||||
LaTeX Font Info: Redeclaring math symbol \Lambda on input line 11.
|
||||
LaTeX Font Info: Redeclaring math symbol \Xi on input line 11.
|
||||
LaTeX Font Info: Redeclaring math symbol \Pi on input line 11.
|
||||
LaTeX Font Info: Redeclaring math symbol \Sigma on input line 11.
|
||||
LaTeX Font Info: Redeclaring math symbol \Upsilon on input line 11.
|
||||
LaTeX Font Info: Redeclaring math symbol \Phi on input line 11.
|
||||
LaTeX Font Info: Redeclaring math symbol \Psi on input line 11.
|
||||
LaTeX Font Info: Redeclaring math symbol \Omega on input line 11.
|
||||
LaTeX Font Info: Redeclaring math symbol \mathdollar on input line 11.
|
||||
LaTeX Font Info: Redeclaring symbol font `operators' on input line 11.
|
||||
LaTeX Font Info: Encoding `OT1' has changed to `TU' for symbol font
|
||||
(Font) `operators' in the math version `normal' on input line 11.
|
||||
LaTeX Font Info: Overwriting symbol font `operators' in version `normal'
|
||||
(Font) OT1/cmr/m/n --> TU/lmr/m/n on input line 11.
|
||||
LaTeX Font Info: Encoding `OT1' has changed to `TU' for symbol font
|
||||
(Font) `operators' in the math version `bold' on input line 11.
|
||||
LaTeX Font Info: Overwriting symbol font `operators' in version `bold'
|
||||
(Font) OT1/cmr/bx/n --> TU/lmr/m/n on input line 11.
|
||||
LaTeX Font Info: Overwriting symbol font `operators' in version `normal'
|
||||
(Font) TU/lmr/m/n --> TU/lmr/m/n on input line 11.
|
||||
LaTeX Font Info: Overwriting math alphabet `\mathit' in version `normal'
|
||||
(Font) OT1/cmr/m/it --> TU/lmr/m/it on input line 11.
|
||||
LaTeX Font Info: Overwriting math alphabet `\mathbf' in version `normal'
|
||||
(Font) OT1/cmr/bx/n --> TU/lmr/b/n on input line 11.
|
||||
LaTeX Font Info: Overwriting math alphabet `\mathsf' in version `normal'
|
||||
(Font) OT1/cmss/m/n --> TU/lmss/m/n on input line 11.
|
||||
LaTeX Font Info: Overwriting math alphabet `\mathtt' in version `normal'
|
||||
(Font) OT1/cmtt/m/n --> TU/HurmitNerdFontMono(0)/m/n on input line 11.
|
||||
LaTeX Font Info: Overwriting symbol font `operators' in version `bold'
|
||||
(Font) TU/lmr/m/n --> TU/lmr/b/n on input line 11.
|
||||
LaTeX Font Info: Overwriting math alphabet `\mathit' in version `bold'
|
||||
(Font) OT1/cmr/bx/it --> TU/lmr/b/it on input line 11.
|
||||
LaTeX Font Info: Overwriting math alphabet `\mathsf' in version `bold'
|
||||
(Font) OT1/cmss/bx/n --> TU/lmss/b/n on input line 11.
|
||||
LaTeX Font Info: Overwriting math alphabet `\mathtt' in version `bold'
|
||||
(Font) OT1/cmtt/m/n --> TU/HurmitNerdFontMono(0)/b/n on input line 11.
|
||||
LaTeX Font Info: External font `cmex10' loaded for size
|
||||
(Font) <7> on input line 14.
|
||||
LaTeX Font Info: External font `cmex10' loaded for size
|
||||
(Font) <5> on input line 14.
|
||||
LaTeX Font Info: Font shape `TU/HurmitNerdFontMono(0)/m/n' will be
|
||||
(Font) scaled to size 6.99997pt on input line 22.
|
||||
[1
|
||||
|
||||
] [2] (./main.aux) )
|
||||
Here is how much of TeX's memory you used:
|
||||
3535 strings out of 476156
|
||||
107058 string characters out of 5814963
|
||||
475344 words of memory out of 5000000
|
||||
24333 multiletter control sequences out of 15000+600000
|
||||
469355 words of font info for 40 fonts, out of 8000000 for 9000
|
||||
1348 hyphenation exceptions out of 8191
|
||||
72i,9n,77p,271b,304s stack positions out of 5000i,500n,10000p,200000b,80000s
|
||||
|
||||
Output written on main.xdv (2 pages, 18856 bytes).
|
||||
Binary file not shown.
Binary file not shown.
@@ -9,7 +9,7 @@
|
||||
}
|
||||
|
||||
\begin{document}
|
||||
\begin{table}[ht]
|
||||
\begin{table}[ht!]
|
||||
\begin{center}
|
||||
\begin{tabular}{|lcl|}
|
||||
\hline
|
||||
@@ -77,14 +77,15 @@
|
||||
\end{center}
|
||||
\end{table}
|
||||
|
||||
\newpage
|
||||
\begin{itemize}
|
||||
\item \textbf{newline}: \\ Newlines are combined, so a single newline is the same as multiple.
|
||||
\item \textbf{module-name}:
|
||||
\item \textbf{id}:
|
||||
\item \textbf{builtin}:
|
||||
\item \textbf{string}:
|
||||
\item \textbf{numeral}:
|
||||
\item \textbf{bool}:
|
||||
\item \textbf{module-name}: \\ Modules are flags given to the interpreter/compiler, to let it know you want to be using certain rules, functions, or features.
|
||||
\item \textbf{id}: \\ Variable. Can only consist of lowercase characters and underscores, but not the letters j, u, or w.
|
||||
\item \textbf{builtin}: \\ Builtin functions are uppercase latin words.
|
||||
\item \textbf{string}: \\ Any text encased in " characters.
|
||||
\item \textbf{numeral}: \\ Roman numerals consisting of the uppercase characters I, V, X, L, C, D, and M. Can also include underscore if the module MAGNVM.
|
||||
\item \textbf{bool}: \\ VERITAS or FALSITAS.
|
||||
\end{itemize}
|
||||
|
||||
\end{document}
|
||||
Binary file not shown.
701
tests.py
Normal file
701
tests.py
Normal file
@@ -0,0 +1,701 @@
|
||||
import random
|
||||
import unittest
|
||||
from io import StringIO
|
||||
from unittest.mock import patch
|
||||
from parameterized import parameterized
|
||||
|
||||
from centvrion.ast_nodes import (
|
||||
Bool, BinOp, BuiltIn, DataArray, DataRangeArray, Defini,
|
||||
Designa, DumStatement, Erumpe, ExpressionStatement, ID,
|
||||
Invoca, ModuleCall, Nullus, Numeral, PerStatement,
|
||||
Program, Redi, SiStatement, String,
|
||||
num_to_int, int_to_num, make_string,
|
||||
)
|
||||
from centvrion.lexer import Lexer
|
||||
from centvrion.parser import Parser
|
||||
from centvrion.values import ValInt, ValStr, ValBool, ValList, ValNul, ValFunc
|
||||
|
||||
def run_test(self, source, target_nodes, target_value, target_output="", input_lines=[]):
|
||||
random.seed(1)
|
||||
|
||||
lexer = Lexer().get_lexer()
|
||||
tokens = lexer.lex(source + "\n")
|
||||
program = Parser().parse(tokens)
|
||||
|
||||
##########################
|
||||
####### Parser Test ###### (commented out — no __eq__ on AST nodes yet)
|
||||
##########################
|
||||
# self.assertEqual(
|
||||
# program,
|
||||
# target_nodes,
|
||||
# f"Parser test:\n{program}\n{target_nodes}"
|
||||
# )
|
||||
|
||||
##########################
|
||||
#### Interpreter Test ####
|
||||
##########################
|
||||
captured = StringIO()
|
||||
try:
|
||||
if input_lines:
|
||||
inputs = iter(input_lines)
|
||||
with patch("builtins.input", lambda: next(inputs)), patch("sys.stdout", captured):
|
||||
result = program.eval()
|
||||
else:
|
||||
with patch("sys.stdout", captured):
|
||||
result = program.eval()
|
||||
except Exception as e:
|
||||
raise e
|
||||
|
||||
self.assertEqual(result, target_value, "Return value test")
|
||||
self.assertEqual(captured.getvalue(), target_output, "Output test")
|
||||
|
||||
##########################
|
||||
###### Printer Test ###### (commented out — no print() on AST nodes yet)
|
||||
##########################
|
||||
# try:
|
||||
# new_text = program.print()
|
||||
# new_tokens = Lexer().get_lexer().lex(new_text + "\n")
|
||||
# new_nodes = Parser().parse(new_tokens)
|
||||
# except Exception as e:
|
||||
# raise Exception(f"###Printer test###\n{new_text}") from e
|
||||
# self.assertEqual(
|
||||
# program,
|
||||
# new_nodes,
|
||||
# f"Printer test\n{source}\n{new_text}"
|
||||
# )
|
||||
|
||||
##########################
|
||||
###### Compiler Test #####
|
||||
##########################
|
||||
# try:
|
||||
# bytecode = program.compile()
|
||||
# ...
|
||||
# except Exception as e:
|
||||
# raise Exception("###Compiler test###") from e
|
||||
|
||||
|
||||
# --- Output ---
|
||||
|
||||
output_tests = [
|
||||
("DICE(\"hello\")", None, ValStr("hello"), "hello\n"),
|
||||
("DICE(\"world\")", None, ValStr("world"), "world\n"),
|
||||
("DICE(III)", None, ValStr("III"), "III\n"),
|
||||
("DICE(X)", None, ValStr("X"), "X\n"),
|
||||
("DICE(MMXXV)", None, ValStr("MMXXV"), "MMXXV\n"),
|
||||
("DICE('hello')", None, ValStr("hello"), "hello\n"),
|
||||
("DICE('world')", None, ValStr("world"), "world\n"),
|
||||
("DICE(\"a\", \"b\")", None, ValStr("a b"), "a b\n"),
|
||||
("DICE(\"line one\")\nDICE(\"line two\")", None, ValStr("line two"), "line one\nline two\n"),
|
||||
("DICE(DICE(II))", None, ValStr("II"), "II\nII\n"),
|
||||
]
|
||||
|
||||
class TestOutput(unittest.TestCase):
|
||||
@parameterized.expand(output_tests)
|
||||
def test_output(self, source, nodes, value, output):
|
||||
run_test(self, source, nodes, value, output)
|
||||
|
||||
|
||||
# --- Arithmetic ---
|
||||
|
||||
arithmetic_tests = [
|
||||
("I + I", None, ValInt(2)),
|
||||
("X - III", None, ValInt(7)),
|
||||
("III * IV", None, ValInt(12)),
|
||||
("X / II", None, ValInt(5)),
|
||||
("X / III", None, ValInt(3)), # integer division: 10 // 3 = 3
|
||||
("II + III * IV", None, ValInt(14)), # precedence: 2 + (3*4) = 14
|
||||
("(II + III) * IV", None, ValInt(20)), # parens: (2+3)*4 = 20
|
||||
]
|
||||
|
||||
class TestArithmetic(unittest.TestCase):
|
||||
@parameterized.expand(arithmetic_tests)
|
||||
def test_arithmetic(self, source, nodes, value):
|
||||
run_test(self, source, nodes, value)
|
||||
|
||||
|
||||
# --- Assignment ---
|
||||
|
||||
assignment_tests = [
|
||||
("DESIGNA x VT III\nx", None, ValInt(3)),
|
||||
("DESIGNA msg VT \"hello\"\nmsg", None, ValStr("hello")),
|
||||
("DESIGNA msg VT 'hello'\nmsg", None, ValStr("hello")),
|
||||
("DESIGNA a VT V\nDESIGNA b VT X\na + b", None, ValInt(15)),
|
||||
("DESIGNA x VT II\nDESIGNA x VT x + I\nx", None, ValInt(3)),
|
||||
]
|
||||
|
||||
class TestAssignment(unittest.TestCase):
|
||||
@parameterized.expand(assignment_tests)
|
||||
def test_assignment(self, source, nodes, value):
|
||||
run_test(self, source, nodes, value)
|
||||
|
||||
|
||||
# --- Control flow ---
|
||||
|
||||
control_tests = [
|
||||
# SI without ALVID — true branch
|
||||
("SI VERITAS TVNC { DESIGNA r VT I }\nr", None, ValInt(1)),
|
||||
# SI without ALVID — false branch
|
||||
("SI FALSITAS TVNC { DESIGNA r VT I }", None, ValNul()),
|
||||
# SI with ALVID — true branch
|
||||
("SI VERITAS TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr", None, ValInt(1)),
|
||||
# SI with ALVID — false branch
|
||||
("SI FALSITAS TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr", None, ValInt(2)),
|
||||
# SI with comparison — equal
|
||||
("SI I EST I TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr", None, ValInt(1)),
|
||||
# SI with comparison — unequal
|
||||
("SI I EST II TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr", None, ValInt(2)),
|
||||
# SI MINVS
|
||||
("SI I MINVS II TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr", None, ValInt(1)),
|
||||
# SI PLVS
|
||||
("SI II PLVS I TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr", None, ValInt(1)),
|
||||
# ALVID SI chain
|
||||
(
|
||||
"SI I EST II TVNC { DESIGNA r VT I } ALVID SI I EST I TVNC { DESIGNA r VT II } ALVID { DESIGNA r VT III }\nr",
|
||||
None, ValInt(2),
|
||||
),
|
||||
# DVM (while not): loops until condition is true
|
||||
(
|
||||
"DESIGNA x VT I\nDVM x EST III FACE {\nDESIGNA x VT x + I\n}\nx",
|
||||
None, ValInt(3),
|
||||
),
|
||||
# DVM with ERVMPE — loop body prints (testing DICE + ERVMPE together)
|
||||
("DESIGNA x VT I\nDVM FALSITAS FACE {\nDICE(x)\nERVMPE\n}", None, ValStr("I"), "I\n"),
|
||||
# PER foreach
|
||||
("PER i IN [(I, II, III)] FACE { DICE(i) }", None, ValStr("III"), "I\nII\nIII\n"),
|
||||
# DONICVM range loop
|
||||
("DONICVM i VT I VSQVE V FACE { DICE(i) }", None, ValStr("IV"), "I\nII\nIII\nIV\n"),
|
||||
]
|
||||
|
||||
class TestControl(unittest.TestCase):
|
||||
@parameterized.expand(control_tests)
|
||||
def test_control(self, source, nodes, value, output=""):
|
||||
run_test(self, source, nodes, value, output)
|
||||
|
||||
|
||||
# --- Functions ---
|
||||
|
||||
function_tests = [
|
||||
(
|
||||
"DEFINI bis (n) VT { REDI (n * II) }\nINVOCA bis (III)",
|
||||
None, ValInt(6),
|
||||
),
|
||||
(
|
||||
"DEFINI add (a, b) VT { REDI (a + b) }\nINVOCA add (III, IV)",
|
||||
None, ValInt(7),
|
||||
),
|
||||
# Fibonacci: fib(n<3)=1, fib(n)=fib(n-1)+fib(n-2)
|
||||
(
|
||||
"DEFINI fib (n) VT {\nSI n MINVS III TVNC { REDI (I) } ALVID { REDI (INVOCA fib (n - I) + INVOCA fib (n - II)) }\n}\nINVOCA fib (VII)",
|
||||
None, ValInt(13),
|
||||
),
|
||||
]
|
||||
|
||||
class TestFunctions(unittest.TestCase):
|
||||
@parameterized.expand(function_tests)
|
||||
def test_functions(self, source, nodes, value):
|
||||
run_test(self, source, nodes, value)
|
||||
|
||||
|
||||
# --- Builtins ---
|
||||
|
||||
builtin_tests = [
|
||||
("AVDI_NVMERVS()", None, ValInt(3), "", ["III"]),
|
||||
("AVDI_NVMERVS()", None, ValInt(10), "", ["X"]),
|
||||
("CVM FORS\nFORTIS_NVMERVS(I, X)", None, ValInt(3)),
|
||||
("AVDI()", None, ValStr("hello"), "", ["hello"]),
|
||||
("LONGITVDO([(I, II, III)])", None, ValInt(3)),
|
||||
("CVM FORS\nFORTIS_ELECTIONIS([(I, II, III)])", None, ValInt(1)),
|
||||
]
|
||||
|
||||
class TestBuiltins(unittest.TestCase):
|
||||
@parameterized.expand(builtin_tests)
|
||||
def test_builtins(self, source, nodes, value, output="", input_lines=[]):
|
||||
run_test(self, source, nodes, value, output, input_lines)
|
||||
|
||||
|
||||
# --- Errors ---
|
||||
|
||||
error_tests = [
|
||||
("x", KeyError), # undefined variable
|
||||
("INVOCA f ()", KeyError), # undefined function
|
||||
("DESIGNA VT III", SyntaxError), # parse error: missing id after DESIGNA
|
||||
("DESIGNA x III", SyntaxError), # parse error: missing VT
|
||||
("DICE(M + M + M + M)", ValueError), # output > 3999 without MAGNVM
|
||||
("IIII", ValueError), # invalid Roman numeral in source
|
||||
("FORTIS_NVMERVS(I, X)", ValueError), # requires FORS module
|
||||
("DEFINI f (x) VT { REDI(x) }\nINVOCA f (I, II)", TypeError), # too many args
|
||||
("DEFINI f (x, y) VT { REDI(x) }\nINVOCA f (I)", TypeError), # too few args
|
||||
("DEFINI f () VT { REDI(I) }\nINVOCA f (I)", TypeError), # args to zero-param function
|
||||
("SI NVLLVS TVNC { DESIGNA r VT I }", TypeError), # NVLLVS cannot be used as boolean
|
||||
]
|
||||
|
||||
class TestErrors(unittest.TestCase):
|
||||
@parameterized.expand(error_tests)
|
||||
def test_errors(self, source, error_type):
|
||||
with self.assertRaises(error_type):
|
||||
run_test(self, source, None, None)
|
||||
|
||||
|
||||
# --- Repr ---
|
||||
|
||||
repr_tests = [
|
||||
("string", String("hello"), "String(hello)"),
|
||||
("numeral", Numeral("III"), "Numeral(III)"),
|
||||
("bool_true", Bool(True), "Bool(True)"),
|
||||
("bool_false", Bool(False), "Bool(False)"),
|
||||
("nullus", Nullus(), "Nullus()"),
|
||||
("erumpe", Erumpe(), "Erumpe()"),
|
||||
("module_call", ModuleCall("FORS"), "FORS"),
|
||||
("id", ID("x"), "ID(x)"),
|
||||
("expression_stmt", ExpressionStatement(String("hi")), "String(hi)"),
|
||||
("data_array", DataArray([Numeral("I"), Numeral("II")]), "Array([\n Numeral(I),\n Numeral(II)\n])"),
|
||||
("data_range_array", DataRangeArray(Numeral("I"), Numeral("X")), "RangeArray([\n Numeral(I),\n Numeral(X)\n])"),
|
||||
("designa", Designa(ID("x"), Numeral("III")), "Designa(\n ID(x),\n Numeral(III)\n)"),
|
||||
("binop", BinOp(Numeral("I"), Numeral("II"), "SYMBOL_PLUS"), "BinOp(\n Numeral(I),\n Numeral(II),\n SYMBOL_PLUS\n)"),
|
||||
("redi", Redi([Numeral("I")]), "Redi([\n Numeral(I)\n])"),
|
||||
("si_no_else", SiStatement(Bool(True), [ExpressionStatement(Erumpe())], None), "Si(\n Bool(True),\n statements([\n Erumpe()\n ]),\n statements([])\n)"),
|
||||
("si_with_else", SiStatement(Bool(True), [ExpressionStatement(Erumpe())], [ExpressionStatement(Erumpe())]), "Si(\n Bool(True),\n statements([\n Erumpe()\n ]),\n statements([\n Erumpe()\n ])\n)"),
|
||||
("dum", DumStatement(Bool(False), [ExpressionStatement(Erumpe())]), "Dum(\n Bool(False),\n statements([\n Erumpe()\n ])\n)"),
|
||||
("per", PerStatement(DataArray([Numeral("I")]), ID("i"), [ExpressionStatement(Erumpe())]), "Per(\n Array([\n Numeral(I)\n ]),\n ID(i),\n statements([\n Erumpe()\n ])\n)"),
|
||||
("invoca", Invoca(ID("f"), [Numeral("I")]), "Invoca(\n ID(f),\n parameters([\n Numeral(I)\n ])\n)"),
|
||||
("builtin", BuiltIn("DICE", [String("hi")]), "Builtin(\n DICE,\n parameters([\n String(hi)\n ])\n)"),
|
||||
("defini", Defini(ID("f"), [ID("n")], [ExpressionStatement(Redi([Numeral("I")]))]), "Defini(\n ID(f),\n parameters([\n ID(n)\n ]),\n statements([\n Redi([\n Numeral(I)\n ])\n ])\n)"),
|
||||
("program_no_modules", Program([], [ExpressionStatement(Numeral("I"))]), "modules([]),\nstatements([\n Numeral(I)\n])"),
|
||||
("program_with_module", Program([ModuleCall("FORS")], [ExpressionStatement(Numeral("I"))]), "modules([\n FORS\n]),\nstatements([\n Numeral(I)\n])"),
|
||||
]
|
||||
|
||||
class TestRepr(unittest.TestCase):
|
||||
@parameterized.expand(repr_tests)
|
||||
def test_repr(self, _, node, expected):
|
||||
self.assertEqual(repr(node), expected)
|
||||
|
||||
|
||||
# --- Roman numeral utilities ---
|
||||
|
||||
class TestNumerals(unittest.TestCase):
|
||||
# num_to_int: valid cases
|
||||
def test_simple_numerals(self):
|
||||
for s, n in [("I",1),("V",5),("X",10),("L",50),("C",100),("D",500),("M",1000)]:
|
||||
self.assertEqual(num_to_int(s, False), n)
|
||||
|
||||
def test_subtractive_forms(self):
|
||||
for s, n in [("IV",4),("IX",9),("XL",40),("XC",90),("CD",400),("CM",900)]:
|
||||
self.assertEqual(num_to_int(s, False), n)
|
||||
|
||||
def test_complex_numerals(self):
|
||||
for s, n in [("XLII",42),("XCIX",99),("MCMXCIX",1999),("MMMCMXCIX",3999)]:
|
||||
self.assertEqual(num_to_int(s, False), n)
|
||||
|
||||
# num_to_int: invalid cases
|
||||
def test_four_in_a_row_raises(self):
|
||||
with self.assertRaises(Exception):
|
||||
num_to_int("IIII", False)
|
||||
|
||||
def test_four_x_in_a_row_raises(self):
|
||||
with self.assertRaises(Exception):
|
||||
num_to_int("XXXX", False)
|
||||
|
||||
def test_invalid_subtractive_iix_raises(self):
|
||||
# IIX is non-standard — I can't appear twice before X
|
||||
with self.assertRaises(Exception):
|
||||
num_to_int("IIX", False)
|
||||
|
||||
def test_invalid_subtractive_im_raises(self):
|
||||
# I can only subtract from V and X, not M
|
||||
with self.assertRaises(Exception):
|
||||
num_to_int("IM", False)
|
||||
|
||||
# int_to_num: valid cases
|
||||
def test_int_to_num(self):
|
||||
for n, s in [(1,"I"),(4,"IV"),(9,"IX"),(40,"XL"),(42,"XLII"),(3999,"MMMCMXCIX")]:
|
||||
self.assertEqual(int_to_num(n, False), s)
|
||||
|
||||
def test_int_to_num_above_3999_raises(self):
|
||||
with self.assertRaises(Exception):
|
||||
int_to_num(4000, False)
|
||||
|
||||
def test_int_to_num_magnvm(self):
|
||||
# 4000 with MAGNVM enabled
|
||||
self.assertEqual(int_to_num(4000, True), "MV_")
|
||||
|
||||
def test_num_to_int_magnvm_required(self):
|
||||
# Numbers parsed from strings with _ require MAGNVM
|
||||
with self.assertRaises(Exception):
|
||||
num_to_int("V_", False)
|
||||
|
||||
|
||||
# --- make_string ---
|
||||
|
||||
class TestMakeString(unittest.TestCase):
|
||||
def test_str(self):
|
||||
self.assertEqual(make_string(ValStr("hello")), "hello")
|
||||
|
||||
def test_int(self):
|
||||
self.assertEqual(make_string(ValInt(3)), "III")
|
||||
|
||||
def test_bool_true(self):
|
||||
self.assertEqual(make_string(ValBool(True)), "VERVS")
|
||||
|
||||
def test_bool_false(self):
|
||||
self.assertEqual(make_string(ValBool(False)), "FALSVS")
|
||||
|
||||
def test_nul(self):
|
||||
self.assertEqual(make_string(ValNul()), "NVLLVS")
|
||||
|
||||
def test_list(self):
|
||||
self.assertEqual(make_string(ValList([ValInt(1), ValInt(2)])), "[I II]")
|
||||
|
||||
def test_empty_list(self):
|
||||
self.assertEqual(make_string(ValList([])), "[]")
|
||||
|
||||
def test_nested_list(self):
|
||||
self.assertEqual(
|
||||
make_string(ValList([ValStr("a"), ValBool(True)])),
|
||||
"[a VERVS]"
|
||||
)
|
||||
|
||||
|
||||
# --- DICE with non-integer types ---
|
||||
|
||||
dice_type_tests = [
|
||||
("DICE(VERITAS)", None, ValStr("VERVS"), "VERVS\n"),
|
||||
("DICE(FALSITAS)", None, ValStr("FALSVS"), "FALSVS\n"),
|
||||
("DICE(NVLLVS)", None, ValStr("NVLLVS"), "NVLLVS\n"),
|
||||
('DICE([(I, II)])', None, ValStr("[I II]"), "[I II]\n"),
|
||||
('DICE("")', None, ValStr(""), "\n"),
|
||||
# arithmetic result printed as numeral
|
||||
("DICE(II + III)", None, ValStr("V"), "V\n"),
|
||||
# multiple args of mixed types
|
||||
('DICE("x", VERITAS)', None, ValStr("x VERVS"), "x VERVS\n"),
|
||||
]
|
||||
|
||||
class TestDiceTypes(unittest.TestCase):
|
||||
@parameterized.expand(dice_type_tests)
|
||||
def test_dice_types(self, source, nodes, value, output):
|
||||
run_test(self, source, nodes, value, output)
|
||||
|
||||
|
||||
# --- SI/DVM: truthiness of non-bool conditions ---
|
||||
|
||||
truthiness_tests = [
|
||||
# nonzero int is truthy
|
||||
("SI I TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr", None, ValInt(1)),
|
||||
# zero int is falsy
|
||||
("DESIGNA z VT I - I\nSI z TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr", None, ValInt(2)),
|
||||
# non-empty list is truthy
|
||||
("SI [(I)] TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr", None, ValInt(1)),
|
||||
# empty list is falsy
|
||||
("SI [()] TVNC { DESIGNA r VT II } ALVID { DESIGNA r VT I }\nr", None, ValInt(1)),
|
||||
# DVM exits when condition becomes truthy
|
||||
(
|
||||
"DESIGNA x VT I\nDVM x PLVS III FACE {\nDESIGNA x VT x + I\n}\nx",
|
||||
None, ValInt(4),
|
||||
),
|
||||
]
|
||||
|
||||
class TestTruthiness(unittest.TestCase):
|
||||
@parameterized.expand(truthiness_tests)
|
||||
def test_truthiness(self, source, nodes, value):
|
||||
run_test(self, source, nodes, value)
|
||||
|
||||
|
||||
# --- Arithmetic: edge cases ---
|
||||
|
||||
arithmetic_edge_tests = [
|
||||
("I - I", None, ValInt(0)), # result zero
|
||||
("I - V", None, ValInt(-4)), # negative result
|
||||
("I / V", None, ValInt(0)), # integer division → 0
|
||||
("M * M", None, ValInt(1000000)), # large intermediate (not displayed)
|
||||
("(I + II) * (IV - I)", None, ValInt(9)), # nested parens
|
||||
]
|
||||
|
||||
class TestArithmeticEdge(unittest.TestCase):
|
||||
@parameterized.expand(arithmetic_edge_tests)
|
||||
def test_arithmetic_edge(self, source, nodes, value):
|
||||
run_test(self, source, nodes, value)
|
||||
|
||||
|
||||
# --- Comparison operators ---
|
||||
|
||||
comparison_tests = [
|
||||
# EST on strings
|
||||
('\"hello\" EST \"hello\"', None, ValBool(True)),
|
||||
('\"hello\" EST \"world\"', None, ValBool(False)),
|
||||
# chain comparisons as conditions
|
||||
("SI III PLVS II TVNC { DESIGNA r VT I }\nr", None, ValInt(1)),
|
||||
("SI II PLVS III TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr", None, ValInt(2)),
|
||||
# result of comparison is ValBool
|
||||
("I EST I", None, ValBool(True)),
|
||||
("I EST II", None, ValBool(False)),
|
||||
("I MINVS II", None, ValBool(True)),
|
||||
("II MINVS I", None, ValBool(False)),
|
||||
("II PLVS I", None, ValBool(True)),
|
||||
("I PLVS II", None, ValBool(False)),
|
||||
]
|
||||
|
||||
class TestComparisons(unittest.TestCase):
|
||||
@parameterized.expand(comparison_tests)
|
||||
def test_comparisons(self, source, nodes, value):
|
||||
run_test(self, source, nodes, value)
|
||||
|
||||
|
||||
# --- Function edge cases ---
|
||||
|
||||
function_edge_tests = [
|
||||
# no explicit REDI → returns ValNul
|
||||
("DEFINI f () VT { I }\nINVOCA f ()", None, ValNul()),
|
||||
# REDI multiple values → ValList
|
||||
(
|
||||
"DEFINI pair (a, b) VT { REDI (a, b) }\nINVOCA pair (I, II)",
|
||||
None, ValList([ValInt(1), ValInt(2)]),
|
||||
),
|
||||
# function doesn't mutate outer vtable
|
||||
(
|
||||
"DESIGNA x VT I\nDEFINI f () VT { DESIGNA x VT V\nREDI (x) }\nINVOCA f ()\nx",
|
||||
None, ValInt(1),
|
||||
),
|
||||
# function can read outer vtable (closure-like)
|
||||
(
|
||||
"DESIGNA x VT VII\nDEFINI f () VT { REDI (x) }\nINVOCA f ()",
|
||||
None, ValInt(7),
|
||||
),
|
||||
# function defined after use is still a parse error (definition must precede call at runtime)
|
||||
# (skipped — ftable is populated at eval time, so definition order matters)
|
||||
# parameter shadows outer variable inside function
|
||||
(
|
||||
"DESIGNA n VT I\nDEFINI f (n) VT { REDI (n * II) }\nINVOCA f (X)\nn",
|
||||
None, ValInt(1),
|
||||
),
|
||||
# function aliasing: assign f to g, invoke via g
|
||||
(
|
||||
"DEFINI f (n) VT { REDI (n * II) }\nDESIGNA g VT f\nINVOCA g (V)",
|
||||
None, ValInt(10),
|
||||
),
|
||||
# alias is independent: redefining f doesn't affect g
|
||||
(
|
||||
"DEFINI f (n) VT { REDI (n * II) }\nDESIGNA g VT f\nDEFINI f (n) VT { REDI (n * III) }\nINVOCA g (V)",
|
||||
None, ValInt(10),
|
||||
),
|
||||
]
|
||||
|
||||
class TestFunctionEdge(unittest.TestCase):
|
||||
@parameterized.expand(function_edge_tests)
|
||||
def test_function_edge(self, source, nodes, value):
|
||||
run_test(self, source, nodes, value)
|
||||
|
||||
|
||||
# --- Loop edge cases ---
|
||||
|
||||
loop_edge_tests = [
|
||||
# range(3, 3) is empty — body never runs, program returns ValNul
|
||||
("DONICVM i VT III VSQVE III FACE { DICE(i) }", None, ValNul(), ""),
|
||||
# empty array — body never runs
|
||||
("PER i IN [()] FACE { DICE(i) }", None, ValNul(), ""),
|
||||
# PER breaks on element 2 — last assigned i is 2
|
||||
("PER i IN [(I, II, III)] FACE { SI i EST II TVNC { ERVMPE } }\ni", None, ValInt(2), ""),
|
||||
# nested DVM: inner always breaks; outer runs until btr==3
|
||||
("DESIGNA btr VT I\nDVM btr EST III FACE {\nDVM FALSITAS FACE {\nERVMPE\n}\nDESIGNA btr VT btr + I\n}\nbtr", None, ValInt(3), ""),
|
||||
# nested PER: inner always breaks on first element; outer completes both iterations
|
||||
# cnt starts at 1, increments twice → 3
|
||||
("DESIGNA cnt VT I\nPER i IN [(I, II)] FACE {\nPER k IN [(I, II)] FACE {\nERVMPE\n}\nDESIGNA cnt VT cnt + I\n}\ncnt", None, ValInt(3), ""),
|
||||
# DVM condition true from start — body never runs
|
||||
("DESIGNA x VT I\nDVM VERITAS FACE {\nDESIGNA x VT x + I\n}\nx", None, ValInt(1), ""),
|
||||
# single iteration: [I VSQVE II] = [1]
|
||||
("DONICVM i VT I VSQVE II FACE { DICE(i) }", None, ValStr("I"), "I\n"),
|
||||
]
|
||||
|
||||
class TestLoopEdge(unittest.TestCase):
|
||||
@parameterized.expand(loop_edge_tests)
|
||||
def test_loop_edge(self, source, nodes, value, output=""):
|
||||
run_test(self, source, nodes, value, output)
|
||||
|
||||
|
||||
# --- Values: equality and truthiness ---
|
||||
|
||||
class TestValues(unittest.TestCase):
|
||||
def test_valint_equality(self):
|
||||
self.assertEqual(ValInt(3), ValInt(3))
|
||||
self.assertNotEqual(ValInt(3), ValInt(4))
|
||||
|
||||
def test_valstr_equality(self):
|
||||
self.assertEqual(ValStr("hi"), ValStr("hi"))
|
||||
self.assertNotEqual(ValStr("hi"), ValStr("bye"))
|
||||
|
||||
def test_valbool_equality(self):
|
||||
self.assertEqual(ValBool(True), ValBool(True))
|
||||
self.assertNotEqual(ValBool(True), ValBool(False))
|
||||
|
||||
def test_valnul_equality(self):
|
||||
self.assertEqual(ValNul(), ValNul())
|
||||
|
||||
def test_vallist_equality(self):
|
||||
self.assertEqual(ValList([ValInt(1)]), ValList([ValInt(1)]))
|
||||
self.assertNotEqual(ValList([ValInt(1)]), ValList([ValInt(2)]))
|
||||
self.assertNotEqual(ValList([ValInt(1)]), ValList([]))
|
||||
|
||||
def test_valint_truthiness(self):
|
||||
self.assertTrue(bool(ValInt(1)))
|
||||
self.assertTrue(bool(ValInt(-1)))
|
||||
self.assertFalse(bool(ValInt(0)))
|
||||
|
||||
def test_valstr_truthiness(self):
|
||||
self.assertTrue(bool(ValStr("x")))
|
||||
self.assertFalse(bool(ValStr("")))
|
||||
|
||||
def test_valbool_truthiness(self):
|
||||
self.assertTrue(bool(ValBool(True)))
|
||||
self.assertFalse(bool(ValBool(False)))
|
||||
|
||||
def test_vallist_truthiness(self):
|
||||
self.assertTrue(bool(ValList([ValInt(1)])))
|
||||
self.assertFalse(bool(ValList([])))
|
||||
|
||||
def test_cross_type_inequality(self):
|
||||
self.assertNotEqual(ValInt(1), ValBool(True))
|
||||
self.assertNotEqual(ValInt(0), ValNul())
|
||||
self.assertNotEqual(ValStr(""), ValNul())
|
||||
|
||||
|
||||
# --- MAGNVM module ---
|
||||
# (ValueError for 4000 without MAGNVM is already in error_tests)
|
||||
|
||||
magnvm_tests = [
|
||||
# M+M+M+M = 4000; MAGNVM allows display as "MV_"
|
||||
("CVM MAGNVM\nDICE(M + M + M + M)", None, ValStr("MV_"), "MV_\n"),
|
||||
# I_ = 1000 with MAGNVM (same value as M, but written with thousands operator)
|
||||
("CVM MAGNVM\nI_", None, ValInt(1000), ""),
|
||||
# I_ + I_ = 2000; displayed as MM with MAGNVM
|
||||
("CVM MAGNVM\nDICE(I_ + I_)", None, ValStr("MM"), "MM\n"),
|
||||
]
|
||||
|
||||
class TestMAGNVM(unittest.TestCase):
|
||||
@parameterized.expand(magnvm_tests)
|
||||
def test_magnvm(self, source, nodes, value, output=""):
|
||||
run_test(self, source, nodes, value, output)
|
||||
|
||||
|
||||
# --- ET and AVT (boolean and/or) ---
|
||||
|
||||
et_avt_tests = [
|
||||
("VERITAS ET VERITAS", None, ValBool(True)),
|
||||
("VERITAS ET FALSITAS", None, ValBool(False)),
|
||||
("FALSITAS ET VERITAS", None, ValBool(False)),
|
||||
("FALSITAS ET FALSITAS", None, ValBool(False)),
|
||||
("VERITAS AVT VERITAS", None, ValBool(True)),
|
||||
("VERITAS AVT FALSITAS", None, ValBool(True)),
|
||||
("FALSITAS AVT VERITAS", None, ValBool(True)),
|
||||
("FALSITAS AVT FALSITAS", None, ValBool(False)),
|
||||
# short-circuit behaviour: combined with comparisons
|
||||
("(I EST I) ET (II EST II)", None, ValBool(True)),
|
||||
("(I EST II) AVT (II EST II)", None, ValBool(True)),
|
||||
# used as SI condition
|
||||
("SI VERITAS ET VERITAS TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr", None, ValInt(1)),
|
||||
("SI FALSITAS AVT FALSITAS TVNC { DESIGNA r VT I } ALVID { DESIGNA r VT II }\nr", None, ValInt(2)),
|
||||
]
|
||||
|
||||
class TestEtAvt(unittest.TestCase):
|
||||
@parameterized.expand(et_avt_tests)
|
||||
def test_et_avt(self, source, nodes, value):
|
||||
run_test(self, source, nodes, value)
|
||||
|
||||
|
||||
# --- Array indexing ---
|
||||
# Indexing is 0-based; NVLLVS serves as index 0
|
||||
|
||||
array_index_tests = [
|
||||
# basic indexing
|
||||
("[(I, II, III)][NVLLVS]", None, ValInt(1)), # index 0 → first element
|
||||
("[(I, II, III)][I]", None, ValInt(2)), # index 1 → second element
|
||||
("[(I, II, III)][II]", None, ValInt(3)), # index 2 → third element
|
||||
# index into a variable
|
||||
("DESIGNA a VT [(X, XX, XXX)]\na[I]", None, ValInt(20)),
|
||||
# index into range array
|
||||
("[I VSQVE V][II]", None, ValInt(3)),
|
||||
]
|
||||
|
||||
class TestArrayIndex(unittest.TestCase):
|
||||
@parameterized.expand(array_index_tests)
|
||||
def test_array_index(self, source, nodes, value):
|
||||
run_test(self, source, nodes, value)
|
||||
|
||||
|
||||
# --- Comments ---
|
||||
|
||||
comment_tests = [
|
||||
# trailing line comment
|
||||
('DICE("hello") // this is ignored', None, ValStr("hello"), "hello\n"),
|
||||
# line comment on its own line before code
|
||||
('// ignored\nDICE("hi")', None, ValStr("hi"), "hi\n"),
|
||||
# inline block comment
|
||||
('DICE(/* ignored */ "hi")', None, ValStr("hi"), "hi\n"),
|
||||
# block comment spanning multiple lines
|
||||
('/* line one\nline two */\nDICE("hi")', None, ValStr("hi"), "hi\n"),
|
||||
# block comment mid-expression
|
||||
("II /* ignored */ + III", None, ValInt(5)),
|
||||
# line comment after expression (no output)
|
||||
("II + III // ignored", None, ValInt(5)),
|
||||
# division still works (/ token not confused with //)
|
||||
("X / II", None, ValInt(5)),
|
||||
# multiple line comments
|
||||
('// first\n// second\nDICE("ok")', None, ValStr("ok"), "ok\n"),
|
||||
# comment-only line between two statements
|
||||
('DESIGNA x VT I\n// set y\nDESIGNA y VT II\nx + y', None, ValInt(3)),
|
||||
# blank line between two statements (double newline)
|
||||
('DESIGNA x VT I\n\nDESIGNA y VT II\nx + y', None, ValInt(3)),
|
||||
# multiple comment-only lines between statements
|
||||
('DESIGNA x VT I\n// one\n// two\nDESIGNA y VT III\nx + y', None, ValInt(4)),
|
||||
]
|
||||
|
||||
class TestComments(unittest.TestCase):
|
||||
@parameterized.expand(comment_tests)
|
||||
def test_comments(self, source, nodes, value, output=""):
|
||||
run_test(self, source, nodes, value, output)
|
||||
|
||||
|
||||
# --- Scope ---
|
||||
|
||||
scope_tests = [
|
||||
# SI: variable assigned in true branch persists in outer scope
|
||||
("SI VERITAS TVNC { DESIGNA r VT X }\nr", None, ValInt(10)),
|
||||
# SI: variable assigned in ALVID branch persists in outer scope
|
||||
("SI FALSITAS TVNC { DESIGNA r VT X } ALVID { DESIGNA r VT V }\nr", None, ValInt(5)),
|
||||
# DVM: variable assigned in body persists after loop exits
|
||||
# x goes 1→2→3→4→5; r tracks x each iteration; loop exits when x==5
|
||||
("DESIGNA x VT I\nDVM x EST V FACE { DESIGNA x VT x + I\nDESIGNA r VT x }\nr", None, ValInt(5)),
|
||||
# PER: loop variable holds last array element after loop (no ERVMPE)
|
||||
("PER i IN [(I, II, III)] FACE { DESIGNA nop VT I }\ni", None, ValInt(3)),
|
||||
# PER: reassigning loop var in body doesn't prevent remaining iterations from running
|
||||
# cnt increments once per iteration (all 3); C=100 doesn't replace next element assignment
|
||||
("DESIGNA cnt VT I\nPER i IN [(I, II, III)] FACE { DESIGNA i VT C\nDESIGNA cnt VT cnt + I }\ncnt", None, ValInt(4)),
|
||||
# PER: loop var after loop reflects the last body assignment, not the last array element
|
||||
# body sets i=C=100 on every iteration; after loop ends, i stays at 100
|
||||
("PER i IN [(I, II, III)] FACE { DESIGNA i VT C }\ni", None, ValInt(100)),
|
||||
# DONICVM: counter holds last range value after loop ends
|
||||
# [I VSQVE IV] = [1,2,3]; last value assigned by loop is III=3
|
||||
("DONICVM i VT I VSQVE IV FACE { DESIGNA nop VT I }\ni", None, ValInt(3)),
|
||||
# DONICVM: reassigning counter inside body doesn't reduce the number of iterations
|
||||
# range [I VSQVE IV] evaluated once; i reset each time; cnt still increments 3 times → 4
|
||||
("DESIGNA cnt VT I\nDONICVM i VT I VSQVE IV FACE { DESIGNA cnt VT cnt + I\nDESIGNA i VT C }\ncnt", None, ValInt(4)),
|
||||
# DONICVM: ERVMPE exits loop early; counter persists at break value
|
||||
("DONICVM i VT I VSQVE X FACE {\nSI i EST III TVNC { ERVMPE }\n}\ni", None, ValInt(3)),
|
||||
# Function: modifying parameter inside function does not affect outer variable of same name
|
||||
# outer n=1; f receives n=5 and modifies its local copy; outer n unchanged
|
||||
("DESIGNA n VT I\nDEFINI f (n) VT { DESIGNA n VT n + X\nREDI (n) }\nINVOCA f (V)\nn", None, ValInt(1)),
|
||||
# Function: mutating outer variable inside function (via DESIGNA) is not visible outside
|
||||
# Invoca creates func_vtable = vtable.copy(); mutations to func_vtable don't propagate back
|
||||
("DESIGNA x VT I\nDEFINI f () VT { DESIGNA x VT C\nREDI (x) }\nINVOCA f ()\nx", None, ValInt(1)),
|
||||
# Function: two successive calls with same parameter name don't share state
|
||||
("DEFINI f (n) VT { REDI (n * II) }\nINVOCA f (III) + INVOCA f (IV)", None, ValInt(14)),
|
||||
# Function: calling f(I) with param named n does not overwrite outer n=II
|
||||
# f is defined before n is designated; INVOCA creates a local copy, outer vtable unchanged
|
||||
("DEFINI f (n) VT { REDI (n * II) }\nDESIGNA n VT II\nINVOCA f (I)\nn", None, ValInt(2)),
|
||||
]
|
||||
|
||||
class TestScope(unittest.TestCase):
|
||||
@parameterized.expand(scope_tests)
|
||||
def test_scope(self, source, nodes, value):
|
||||
run_test(self, source, nodes, value)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -1,11 +0,0 @@
|
||||
DEFINI fib(x) VT {
|
||||
SI x EST NVLLVS TVNC {
|
||||
REDI(NVLLVS)
|
||||
} ALVID SI x EST I TVNC {
|
||||
REDI(I)
|
||||
} ALVID {
|
||||
REDI(INVOCA fib(x-II) + INVOCA fib(x-I))
|
||||
}
|
||||
}
|
||||
|
||||
DICE(INVOCA fib(AVDI_NVMERVS()))
|
||||
@@ -1 +0,0 @@
|
||||
X
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "centvrion",
|
||||
"displayName": "centvrion",
|
||||
"description": "",
|
||||
"description": "Latin-inspired esoteric programming language with Roman numeral literals",
|
||||
"version": "0.0.1",
|
||||
"engines": {
|
||||
"vscode": "^1.68.0"
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
"patterns": [
|
||||
{
|
||||
"name": "keyword.control.cent",
|
||||
"match": "\\b(ALVID|DEFINI|DESIGNA|DONICVM|DVM|ERVMPE|FACE|INVOCA|IN|PER|SI|TVNC|VSQVE|VT|CVM)\\b"
|
||||
"match": "\\b(ALVID|AVT|DEFINI|DESIGNA|DONICVM|DVM|ERVMPE|ET|FACE|INVOCA|IN|PER|SI|TVNC|VSQVE|VT|CVM)\\b"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.comparison.cent",
|
||||
|
||||
Reference in New Issue
Block a user