This commit is contained in:
NikolajDanger
2022-06-16 17:37:07 +02:00
parent 188047f928
commit 48e8bf97fb
13 changed files with 397 additions and 127 deletions

View File

@@ -13,13 +13,13 @@ DICE x
### Recursive Fibonacci number function ### Recursive Fibonacci number function
``` ```
DEFINI fib x VT { DEFINI fib(x) VT {
SI x EST NVLLVS TVNC { SI x EST NVLLVS TVNC {
REDI NVLLVS REDI(NVLLVS)
} ALVID SI x EST I TVNC { } ALVID SI x EST I TVNC {
REDI I REDI(I)
} ALVID { } ALVID {
REDI ((INVOCA fib (x-II)) + (INVOCA fib (x-I))) REDI(INVOCA fib(x-II) + INVOCA fib(x-I))
} }
} }
``` ```
@@ -29,21 +29,21 @@ DEFINI fib x VT {
``` ```
CVM FORS CVM FORS
DESIGNA correct VT FORTIS_NVMERVS I C DESIGNA correct VT FORTIS_NVMERVS(I,C)
DESIGNA gvess VT NVLLVS DESIGNA gvess VT NVLLVS
DVM FALSITAS FACE { DVM FALSITAS FACE {
DESIGNA gvess VT AVDI_NVMERVS DESIGNA gvess VT AVDI_NVMERVS()
SI gvess MINVS correct TVNC { SI gvess MINVS correct TVNC {
DICE "Too low!" DICE("Too low!")
} ALVID SI gvess PLVS correct TVNC { } ALVID SI gvess PLVS correct TVNC {
DICE "Too high!" DICE("Too high!")
} ALVID { } ALVID {
ERVMPE ERVMPE
} }
} }
DICE "You guessed correctly!" DICE("You guessed correctly!")
``` ```
## Variables ## Variables
@@ -109,8 +109,8 @@ If-then statements are denoted with the keywords `SI` (if) and `TVNC` (then). Th
``` ```
DESIGNA x VT VERITAS DESIGNA x VT VERITAS
SI x TVNC { SI x TVNC {
DICE I DICE(I)
REDI NVLLLVS REDI(NVLLLVS)
} }
DICE NVLLVS DICE NVLLVS
@@ -130,9 +130,9 @@ When using `SI`/`TVNC` statements, you can also use `ALVID` as an "else".
``` ```
DESIGNA x VT VERITAS DESIGNA x VT VERITAS
SI x TVNC { SI x TVNC {
DICE I DICE(I)
} ALVID { } ALVID {
DICE NVLLVS DICE(NVLLVS)
} }
> I > I
@@ -143,11 +143,11 @@ SI x TVNC {
``` ```
DESIGNA x VT II DESIGNA x VT II
SI x EST I TVNC SI x EST I TVNC
DICE I DICE(I)
ALVID SI x EST II TVNC ALVID SI x EST II TVNC
DICE II DICE(II)
ALVID ALVID
DICE III DICE(III)
> II > II
``` ```
@@ -160,11 +160,11 @@ The keyword `ET` can be used as a boolean "and". The keyword `AVT` can be used a
DESIGNA x VT VERITAS DESIGNA x VT VERITAS
DESIGNA y VT FALSITAS DESIGNA y VT FALSITAS
SI x ET y TVNC { SI x ET y TVNC {
DICE I DICE(I)
} ALVID SI x AVT y TVNC { } ALVID SI x AVT y TVNC {
DICE II DICE(II)
} ALVID { } ALVID {
DICE III DICE(III)
} }
> II > II
@@ -178,7 +178,7 @@ DESIGNA x VT NVLLVS
DONICVM y VT NVLLVS VSQVE X FACE { DONICVM y VT NVLLVS VSQVE X FACE {
DESIGNA x VT x + y DESIGNA x VT x + y
} }
DICE x DICE(x)
> XLV > XLV
``` ```
@@ -189,7 +189,7 @@ DESIGNA x VT NVLLVS
DVM x PLVS X FACE { DVM x PLVS X FACE {
DESIGNA x VT x+I DESIGNA x VT x+I
} }
DICE x DICE(x)
> XI > XI
``` ```
@@ -198,7 +198,7 @@ DICE x
``` ```
DESIGNA x VT [I, II, III, IV, V] DESIGNA x VT [I, II, III, IV, V]
PER y IN x FACE { PER y IN x FACE {
DICE y DICE(y)
} }
> I > I
@@ -215,10 +215,10 @@ Calling a function is done with the `INVOCA` keyword.
``` ```
DEFINI square x VT { DEFINI square x VT {
REDI (x*x) REDI(x*x)
} }
DICE (INVOCA square XI) DICE(INVOCA square(XI))
> CXXI > CXXI
``` ```

View File

@@ -50,7 +50,7 @@ def num_to_int(n, m):
nums = [single_num_to_int(i, m) for i in chars] nums = [single_num_to_int(i, m) for i in chars]
new_nums = nums.copy() new_nums = nums.copy()
for x, num in enumerate(nums[:-3]): for x, num in enumerate(nums[:-3]):
if all(num == nums[x+i] for i in range(0,3)): if all(num == nums[x+i] for i in range(0,4)):
raise Exception(n, "is not a valid roman numeral") raise Exception(n, "is not a valid roman numeral")
while True: while True:

View File

@@ -58,7 +58,8 @@ symbol_tokens = [
("SYMBOL_PLUS", r"\+"), ("SYMBOL_PLUS", r"\+"),
("SYMBOL_MINUS", r"\-"), ("SYMBOL_MINUS", r"\-"),
("SYMBOL_TIMES", r"\*"), ("SYMBOL_TIMES", r"\*"),
("SYMBOL_DIVIDE", r"\/") ("SYMBOL_DIVIDE", r"\/"),
("SYMBOL_COMMA", r",")
] ]
whitespace_tokens = [ whitespace_tokens = [

View File

@@ -17,27 +17,24 @@ class Parser():
) )
def parse(self, tokens_input) -> ast_nodes.BaseBox: def parse(self, tokens_input) -> ast_nodes.BaseBox:
@self.pg.production('program : opt_newline opt_module_calls opt_newline opt_statements opt_newline')
# Top-level program stuff
@self.pg.production('program : opt_newline module_calls statement_list')
def program(tokens): def program(tokens):
return ast_nodes.Program(tokens[1], tokens[3]) return ast_nodes.Program(tokens[1], tokens[2])
@self.pg.production('opt_newline : ') @self.pg.production('opt_newline : ')
@self.pg.production('opt_newline : NEWLINE') @self.pg.production('opt_newline : NEWLINE')
def opt_newline(_): def opt_newline(_):
return None return None
@self.pg.production('opt_module_calls : ') # Module calls
@self.pg.production('opt_module_calls : module_calls') @self.pg.production('module_calls : ')
def opt_module_calls(calls):
if len(calls) == 0:
return calls
else:
return calls[0]
@self.pg.production('module_calls : module_call NEWLINE ')
@self.pg.production('module_calls : module_call NEWLINE module_calls') @self.pg.production('module_calls : module_call NEWLINE module_calls')
def module_calls(calls): def module_calls(calls):
if len(calls) == 2: if len(calls) == 0:
return []
elif len(calls) == 1:
return [calls[0]] return [calls[0]]
else: else:
return [calls[0]] + calls[2] return [calls[0]] + calls[2]
@@ -47,17 +44,14 @@ class Parser():
return ast_nodes.ModuleCall(tokens[1].value) return ast_nodes.ModuleCall(tokens[1].value)
@self.pg.production('opt_statements : ') # Statements
@self.pg.production('opt_statements : statements') @self.pg.production('statements : opt_newline statement_list')
def opt_statements(calls): def statements(tokens):
if len(calls) == 0: return tokens[1]
return calls
else:
return calls[0]
@self.pg.production('statements : statement NEWLINE ') @self.pg.production('statement_list : statement opt_newline')
@self.pg.production('statements : statement NEWLINE statements') @self.pg.production('statement_list : statement NEWLINE statement_list')
def statements(calls): def statement_list(calls):
if len(calls) == 2: if len(calls) == 2:
return [calls[0]] return [calls[0]]
else: else:
@@ -71,33 +65,77 @@ class Parser():
def statement_expression(tokens): def statement_expression(tokens):
return ast_nodes.ExpressionStatement(tokens[0]) return ast_nodes.ExpressionStatement(tokens[0])
@self.pg.production('expressions : ') @self.pg.production('statement : KEYWORD_DEFINI id ids KEYWORD_VT SYMBOL_LCURL statements SYMBOL_RCURL')
@self.pg.production('expressions : expression expressions') def defini(tokens):
def expressions(calls): return ast_nodes.Defini(tokens[1], tokens[2], tokens[5])
if len(calls) == 0:
return []
else:
return [calls[0]] + calls[1]
@self.pg.production('ids : ') @self.pg.production('statement : KEYWORD_REDI expressions')
@self.pg.production('ids : id ids') def redi(tokens):
def ids(calls): return ast_nodes.Redi(tokens[1])
if len(calls) == 0:
return [] @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('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: else:
return [calls[0]] + calls[1] 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 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('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])
# 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 : id') @self.pg.production('expression : id')
def expression_id(tokens): def expression_id(tokens):
return tokens[0] return tokens[0]
@self.pg.production('statement : KEYWORD_DEFINI id ids KEYWORD_VT SYMBOL_LCURL opt_newline opt_statements opt_newline SYMBOL_RCURL') @self.pg.production('expression : BUILTIN expressions')
def defini(tokens): def expression_builtin(tokens):
return ast_nodes.Defini(tokens[1], tokens[2], tokens[6]) return ast_nodes.BuiltIn(tokens[0].value, tokens[1])
@self.pg.production('statement : KEYWORD_REDI expressions')
def redi(tokens):
return ast_nodes.Redi(tokens[1])
@self.pg.production('expression : DATA_STRING') @self.pg.production('expression : DATA_STRING')
def expression_string(tokens): def expression_string(tokens):
@@ -126,61 +164,10 @@ class Parser():
def binop(tokens): def binop(tokens):
return ast_nodes.BinOp(tokens[0], tokens[2], tokens[1].name) return ast_nodes.BinOp(tokens[0], tokens[2], tokens[1].name)
@self.pg.production('expression : BUILTIN expressions')
def expression_builtin(tokens):
return ast_nodes.BuiltIn(tokens[0].value, tokens[1])
@self.pg.production("id : ID")
def id_expression(tokens):
return ast_nodes.ID(tokens[0].value)
@self.pg.production('expression : KEYWORD_INVOCA id expressions') @self.pg.production('expression : KEYWORD_INVOCA id expressions')
def invoca(tokens): def invoca(tokens):
return ast_nodes.Invoca(tokens[1], tokens[2]) return ast_nodes.Invoca(tokens[1], tokens[2])
@self.pg.production('statement : si_statement')
def si_statement(tokens):
return tokens[0]
@self.pg.production('statement : per_statement')
@self.pg.production('statement : dum_statement')
@self.pg.production('statement : donicum_statement')
def loops(tokens):
return tokens[0]
@self.pg.production('statement : KEYWORD_ERVMPE')
def erumpe(_):
return ast_nodes.Erumpe()
@self.pg.production('si_statement : KEYWORD_SI expression KEYWORD_TVNC SYMBOL_LCURL opt_newline opt_statements opt_newline SYMBOL_RCURL opt_newline aluid_statement')
def si(tokens):
return ast_nodes.SiStatement(tokens[1], tokens[5], tokens[9])
@self.pg.production('dum_statement : KEYWORD_DVM expression KEYWORD_FACE SYMBOL_LCURL opt_newline opt_statements opt_newline SYMBOL_RCURL')
def dum(tokens):
return ast_nodes.DumStatement(tokens[1], tokens[5])
@self.pg.production('per_statement : KEYWORD_PER id KEYWORD_IN expression KEYWORD_FACE SYMBOL_LCURL opt_newline opt_statements opt_newline SYMBOL_RCURL')
def per(tokens):
return ast_nodes.PerStatement(tokens[3], tokens[1], tokens[7])
@self.pg.production('donicum_statement : KEYWORD_DONICVM id KEYWORD_VT expression KEYWORD_VSQVE expression KEYWORD_FACE SYMBOL_LCURL opt_newline opt_statements opt_newline SYMBOL_RCURL')
def donicum(tokens):
range_array = ast_nodes.DataRangeArray(tokens[3], tokens[5])
return ast_nodes.PerStatement(range_array, tokens[1], tokens[9])
@self.pg.production('aluid_statement : ')
def aluid_empty(_):
return None
@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 opt_newline opt_statements opt_newline SYMBOL_RCURL aluid_statement')
def aluid(tokens):
return tokens[3]
@self.pg.production('expression : SYMBOL_LPARENS expression SYMBOL_RPARENS') @self.pg.production('expression : SYMBOL_LPARENS expression SYMBOL_RPARENS')
def parens(tokens): def parens(tokens):
return tokens[1] return tokens[1]
@@ -193,9 +180,29 @@ class Parser():
def range_array(tokens): def range_array(tokens):
return ast_nodes.DataRangeArray(tokens[1], tokens[3]) return ast_nodes.DataRangeArray(tokens[1], tokens[3])
# @self.pg.error # ids
# def error_handle(token): @self.pg.production('ids : SYMBOL_LPARENS id_list')
# raise ValueError(token) 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 : 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)
parser = self.pg.build() parser = self.pg.build()
return parser.parse(tokens_input) return parser.parse(tokens_input)

View File

@@ -1,11 +1,11 @@
DEFINI fib x VT { DEFINI fib(x) VT {
SI x EST NVLLVS TVNC { SI x EST NVLLVS TVNC {
REDI NVLLVS REDI(NVLLVS)
} ALVID SI x EST I TVNC { } ALVID SI x EST I TVNC {
REDI I REDI(I)
} ALVID { } ALVID {
REDI ((INVOCA fib (x-II)) + (INVOCA fib (x-I))) REDI(INVOCA fib(x-II) + INVOCA fib(x-I))
} }
} }
DICE INVOCA fib (AVDI_NVMERVS) DICE(INVOCA fib(AVDI_NVMERVS()))

17
tests/guessing.cent Normal file
View File

@@ -0,0 +1,17 @@
CVM FORS
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
}
}
DICE("You guessed correctly!")

View File

@@ -0,0 +1,4 @@
.vscode/**
.vscode-test/**
.gitignore
vsc-extension-quickstart.md

View File

@@ -0,0 +1,9 @@
# Change Log
All notable changes to the "centvrion" extension will be documented in this file.
Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
## [Unreleased]
- Initial release

View File

@@ -0,0 +1,65 @@
# centvrion README
This is the README for your extension "centvrion". After writing up a brief description, we recommend including the following sections.
## Features
Describe specific features of your extension including screenshots of your extension in action. Image paths are relative to this README file.
For example if there is an image subfolder under your extension project workspace:
\!\[feature X\]\(images/feature-x.png\)
> Tip: Many popular extensions utilize animations. This is an excellent way to show off your extension! We recommend short, focused animations that are easy to follow.
## Requirements
If you have any requirements or dependencies, add a section describing those and how to install and configure them.
## Extension Settings
Include if your extension adds any VS Code settings through the `contributes.configuration` extension point.
For example:
This extension contributes the following settings:
* `myExtension.enable`: enable/disable this extension
* `myExtension.thing`: set to `blah` to do something
## Known Issues
Calling out known issues can help limit users opening duplicate issues against your extension.
## Release Notes
Users appreciate release notes as you update your extension.
### 1.0.0
Initial release of ...
### 1.0.1
Fixed issue #.
### 1.1.0
Added features X, Y, and Z.
-----------------------------------------------------------------------------------------------------------
## Working with Markdown
**Note:** You can author your README using Visual Studio Code. Here are some useful editor keyboard shortcuts:
* Split the editor (`Cmd+\` on macOS or `Ctrl+\` on Windows and Linux)
* Toggle preview (`Shift+CMD+V` on macOS or `Shift+Ctrl+V` on Windows and Linux)
* Press `Ctrl+Space` (Windows, Linux) or `Cmd+Space` (macOS) to see a list of Markdown snippets
### For more information
* [Visual Studio Code's Markdown Support](http://code.visualstudio.com/docs/languages/markdown)
* [Markdown Syntax Reference](https://help.github.com/articles/markdown-basics/)
**Enjoy!**

View File

@@ -0,0 +1,30 @@
{
"comments": {
// symbol used for single line comment. Remove this entry if your language does not support line comments
"lineComment": "//",
// symbols used for start and end a block comment. Remove this entry if your language does not support block comments
"blockComment": [ "/*", "*/" ]
},
// symbols used as brackets
"brackets": [
["{", "}"],
["[", "]"],
["(", ")"]
],
// symbols that are auto closed when typing
"autoClosingPairs": [
["{", "}"],
["[", "]"],
["(", ")"],
["\"", "\""],
["'", "'"]
],
// symbols that can be used to surround a selection
"surroundingPairs": [
["{", "}"],
["[", "]"],
["(", ")"],
["\"", "\""],
["'", "'"]
]
}

View File

@@ -0,0 +1,25 @@
{
"name": "centvrion",
"displayName": "centvrion",
"description": "",
"version": "0.0.1",
"engines": {
"vscode": "^1.68.0"
},
"categories": [
"Programming Languages"
],
"contributes": {
"languages": [{
"id": "cent",
"aliases": ["CENTVRION", "cent"],
"extensions": [".cent"],
"configuration": "./language-configuration.json"
}],
"grammars": [{
"language": "cent",
"scopeName": "source.cent",
"path": "./syntaxes/cent.tmLanguage.json"
}]
}
}

View File

@@ -0,0 +1,83 @@
{
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
"name": "CENTVRION",
"patterns": [
{
"include": "#strings"
},
{
"include": "#keywords"
},
{
"include": "#builtins"
},
{
"include": "#constants"
},
{
"include": "#variables"
}
],
"repository": {
"keywords": {
"patterns": [
{
"name": "keyword.control.cent",
"match": "\\b(ALVID|DEFINI|DESIGNA|DONICVM|DVM|ERVMPE|FACE|INVOCA|IN|PER|SI|TVNC|VSQVE|VT|CVM)\\b"
},
{
"name": "keyword.operator.comparison.cent",
"match": "\\b(EST|MINVS|PLVS)\\b"
},
{
"name": "keyword.operator.arithmetic.cent",
"match": "(\\*|\\+|-|/)"
}
]
},
"builtins": {
"patterns": [
{
"name": "support.function.builtin.cent",
"match": "\\b(AVDI_NVMERVS|AVDI|DICE|FORTIS_NVMERVS|FORTIS_ELECTIONIS|LONGITVDO|REDI)\\b"
}
]
},
"constants": {
"patterns": [
{
"name": "constant.numeric.roman.cent",
"match": "\\b[IVXLCDM]+\\b"
},
{
"name": "constant.language.roman.cent",
"match": "\\b(VERITAS|FALSITAS)\\b"
},
{
"name": "constant.numeric.nullus.cent",
"match": "\\bNVLLVS\\b"
}
]
},
"strings": {
"name": "string.quoted.double.cent",
"begin": "\"",
"end": "\"",
"patterns": [
{
"name": "constant.character.escape.cent",
"match": "\\\\."
}
]
},
"variables": {
"patterns": [
{
"name": "variable.language.cent",
"match": "\\b[abcdefghiklmnopqrstvxyz_]+\\b"
}
]
}
},
"scopeName": "source.cent"
}

View File

@@ -0,0 +1,29 @@
# Welcome to your VS Code Extension
## What's in the folder
* This folder contains all of the files necessary for your extension.
* `package.json` - this is the manifest file in which you declare your language support and define the location of the grammar file that has been copied into your extension.
* `syntaxes/cent.tmLanguage.json` - this is the Text mate grammar file that is used for tokenization.
* `language-configuration.json` - this is the language configuration, defining the tokens that are used for comments and brackets.
## Get up and running straight away
* Make sure the language configuration settings in `language-configuration.json` are accurate.
* Press `F5` to open a new window with your extension loaded.
* Create a new file with a file name suffix matching your language.
* Verify that syntax highlighting works and that the language configuration settings are working.
## Make changes
* You can relaunch the extension from the debug toolbar after making changes to the files listed above.
* You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes.
## Add more language features
* To add features such as intellisense, hovers and validators check out the VS Code extenders documentation at https://code.visualstudio.com/docs
## Install your extension
* To start using your extension with Visual Studio Code copy it into the `<user home>/.vscode/extensions` folder and restart Code.
* To share your extension with the world, read on https://code.visualstudio.com/docs about publishing an extension.