mirror of
https://github.com/Nexoniarz/Finch.git
synced 2026-11-03 00:44:27 +00:00
Finch 2.4.0: methods, maps, errors as values; str() of any value; macOS and ARM64 docs; Kate support
- fn Struct.method(...) with self by reference, also on C structs
- map[K]V: insertion-ordered hash maps, literals, m[k] += 1, has/get/remove/keys/values
- -> T! / -> !, return error(...), or <value>, or { err }, try; fallible int/float/read_file/write_file/delete_file
- for i, x in list / for k, v in map
- print and str() share one text formatter
- LSP: method and map completion, method signatures; grammar and snippets for VS Code and Kate
- tests: 74 (methods, errors, maps + 11 failure cases); docs at all three levels, en and pl
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
fd86eb885c
commit
b872be3176
55 changed files with 3400 additions and 336 deletions
|
|
@ -5,7 +5,7 @@
|
|||
Install: copy to ~/.local/share/org.kde.syntax-highlighting/syntax/finch.xml
|
||||
(or run editors/kate/install.sh), then restart Kate.
|
||||
-->
|
||||
<language name="Finch" version="1" kateversion="5.0" section="Sources" extensions="*.fch"
|
||||
<language name="Finch" version="2" kateversion="5.0" section="Sources" extensions="*.fch"
|
||||
mimetype="text/x-finch" indenter="cstyle" author="The Finch authors" license="Apache-2.0">
|
||||
<highlighting>
|
||||
<list name="keywords">
|
||||
|
|
@ -22,6 +22,8 @@
|
|||
<item>continue</item>
|
||||
<item>return</item>
|
||||
<item>defer</item>
|
||||
<item>or</item>
|
||||
<item>try</item>
|
||||
</list>
|
||||
<list name="imports">
|
||||
<item>import</item>
|
||||
|
|
@ -31,6 +33,7 @@
|
|||
<item>true</item>
|
||||
<item>false</item>
|
||||
<item>null</item>
|
||||
<item>self</item>
|
||||
</list>
|
||||
<list name="types">
|
||||
<item>int</item>
|
||||
|
|
@ -39,6 +42,7 @@
|
|||
<item>char</item>
|
||||
<item>str</item>
|
||||
<item>ptr</item>
|
||||
<item>map</item>
|
||||
<item>i8</item>
|
||||
<item>i16</item>
|
||||
<item>i32</item>
|
||||
|
|
@ -62,6 +66,7 @@
|
|||
<item>addr</item>
|
||||
<item>new</item>
|
||||
<item>free</item>
|
||||
<item>error</item>
|
||||
</list>
|
||||
|
||||
<contexts>
|
||||
|
|
@ -99,8 +104,11 @@
|
|||
<AnyChar String="()[],.:" attribute="Symbol"/>
|
||||
</context>
|
||||
|
||||
<!-- fn name( or fn Type.method( -->
|
||||
<context name="FunctionName" attribute="Normal Text" lineEndContext="#pop" fallthroughContext="#pop">
|
||||
<DetectSpaces/>
|
||||
<RegExpr String="[A-Za-z_][A-Za-z0-9_]*(?=\.)" attribute="Data Type"/>
|
||||
<DetectChar char="." attribute="Symbol"/>
|
||||
<RegExpr String="[A-Za-z_][A-Za-z0-9_]*" attribute="Function Definition" context="#pop"/>
|
||||
</context>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,11 @@
|
|||
# Changelog
|
||||
|
||||
## 2.4.0
|
||||
|
||||
- Highlighting for methods (`fn Point.move`), maps (`map[K]V`), `or`, `try`, `self` and `error(...)`.
|
||||
- Completion for struct methods and map methods; parameter hints for method calls.
|
||||
- Snippets: `method`, `fnf` (a function that can fail), `map`, `forkv`, `orb`.
|
||||
|
||||
## 2.3.0
|
||||
|
||||
- First release: highlighting, snippets, language server, Run and Build.
|
||||
|
|
|
|||
4
editors/vscode/package-lock.json
generated
4
editors/vscode/package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "finch-lang",
|
||||
"version": "2.3.0",
|
||||
"version": "2.4.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "finch-lang",
|
||||
"version": "2.3.0",
|
||||
"version": "2.4.0",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"vscode-languageclient": "^9.0.1"
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"name": "finch-lang",
|
||||
"displayName": "Finch",
|
||||
"description": "The Finch programming language: highlighting, errors as you type, completion, hover, go to definition, and a Run button.",
|
||||
"version": "2.3.0",
|
||||
"version": "2.4.0",
|
||||
"publisher": "nexoniarz",
|
||||
"license": "Apache-2.0",
|
||||
"icon": "images/icon.png",
|
||||
|
|
|
|||
|
|
@ -1,16 +1,160 @@
|
|||
{
|
||||
"main": { "prefix": "main", "body": ["fn main() {", "\t$0", "}"], "description": "The program's start" },
|
||||
"main with arguments": { "prefix": "mainargs", "body": ["fn main([]str args) {", "\t$0", "}"], "description": "main that gets the command-line arguments" },
|
||||
"function": { "prefix": "fn", "body": ["fn ${1:name}(${2}) {", "\t$0", "}"], "description": "A function" },
|
||||
"function with result": { "prefix": "fnr", "body": ["fn ${1:name}(${2}) -> ${3:int} {", "\t$0", "}"], "description": "A function that returns a value" },
|
||||
"struct": { "prefix": "struct", "body": ["struct ${1:Name} {", "\t${2:int} ${3:field}", "}"], "description": "A struct" },
|
||||
"if": { "prefix": "if", "body": ["if ${1:condition} {", "\t$0", "}"] },
|
||||
"if else": { "prefix": "ife", "body": ["if ${1:condition} {", "\t$2", "} else {", "\t$0", "}"] },
|
||||
"for range": { "prefix": "for", "body": ["for ${1:i} in ${2:0}..${3:n} {", "\t$0", "}"], "description": "Count from start to end-1" },
|
||||
"for each": { "prefix": "foreach", "body": ["for ${1:item} in ${2:list} {", "\t$0", "}"], "description": "Every element of an array or str" },
|
||||
"while": { "prefix": "while", "body": ["while ${1:condition} {", "\t$0", "}"] },
|
||||
"print": { "prefix": "print", "body": ["print(${1})"] },
|
||||
"input": { "prefix": "input", "body": ["${1:answer} := input(\"${2:Question? }\")"] },
|
||||
"import C header": { "prefix": "importc", "body": ["import \"${1:stdio.h}\""] },
|
||||
"defer": { "prefix": "defer", "body": ["defer ${1}"], "description": "Run this when the block ends" }
|
||||
"main": {
|
||||
"prefix": "main",
|
||||
"body": [
|
||||
"fn main() {",
|
||||
"\t$0",
|
||||
"}"
|
||||
],
|
||||
"description": "The program's start"
|
||||
},
|
||||
"main with arguments": {
|
||||
"prefix": "mainargs",
|
||||
"body": [
|
||||
"fn main([]str args) {",
|
||||
"\t$0",
|
||||
"}"
|
||||
],
|
||||
"description": "main that gets the command-line arguments"
|
||||
},
|
||||
"function": {
|
||||
"prefix": "fn",
|
||||
"body": [
|
||||
"fn ${1:name}(${2}) {",
|
||||
"\t$0",
|
||||
"}"
|
||||
],
|
||||
"description": "A function"
|
||||
},
|
||||
"function with result": {
|
||||
"prefix": "fnr",
|
||||
"body": [
|
||||
"fn ${1:name}(${2}) -> ${3:int} {",
|
||||
"\t$0",
|
||||
"}"
|
||||
],
|
||||
"description": "A function that returns a value"
|
||||
},
|
||||
"struct": {
|
||||
"prefix": "struct",
|
||||
"body": [
|
||||
"struct ${1:Name} {",
|
||||
"\t${2:int} ${3:field}",
|
||||
"}"
|
||||
],
|
||||
"description": "A struct"
|
||||
},
|
||||
"if": {
|
||||
"prefix": "if",
|
||||
"body": [
|
||||
"if ${1:condition} {",
|
||||
"\t$0",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
"if else": {
|
||||
"prefix": "ife",
|
||||
"body": [
|
||||
"if ${1:condition} {",
|
||||
"\t$2",
|
||||
"} else {",
|
||||
"\t$0",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
"for range": {
|
||||
"prefix": "for",
|
||||
"body": [
|
||||
"for ${1:i} in ${2:0}..${3:n} {",
|
||||
"\t$0",
|
||||
"}"
|
||||
],
|
||||
"description": "Count from start to end-1"
|
||||
},
|
||||
"for each": {
|
||||
"prefix": "foreach",
|
||||
"body": [
|
||||
"for ${1:item} in ${2:list} {",
|
||||
"\t$0",
|
||||
"}"
|
||||
],
|
||||
"description": "Every element of an array or str"
|
||||
},
|
||||
"while": {
|
||||
"prefix": "while",
|
||||
"body": [
|
||||
"while ${1:condition} {",
|
||||
"\t$0",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
"print": {
|
||||
"prefix": "print",
|
||||
"body": [
|
||||
"print(${1})"
|
||||
]
|
||||
},
|
||||
"input": {
|
||||
"prefix": "input",
|
||||
"body": [
|
||||
"${1:answer} := input(\"${2:Question? }\")"
|
||||
]
|
||||
},
|
||||
"import C header": {
|
||||
"prefix": "importc",
|
||||
"body": [
|
||||
"import \"${1:stdio.h}\""
|
||||
]
|
||||
},
|
||||
"defer": {
|
||||
"prefix": "defer",
|
||||
"body": [
|
||||
"defer ${1}"
|
||||
],
|
||||
"description": "Run this when the block ends"
|
||||
},
|
||||
"method": {
|
||||
"prefix": "method",
|
||||
"body": [
|
||||
"fn ${1:Type}.${2:name}(${3}) {",
|
||||
"\t$0",
|
||||
"}"
|
||||
],
|
||||
"description": "A method: self is the struct it is called on"
|
||||
},
|
||||
"fallible function": {
|
||||
"prefix": "fnf",
|
||||
"body": [
|
||||
"fn ${1:name}(${2}) -> ${3:int}! {",
|
||||
"\t$0",
|
||||
"}"
|
||||
],
|
||||
"description": "A function that can fail: return error(\"...\")"
|
||||
},
|
||||
"map": {
|
||||
"prefix": "map",
|
||||
"body": [
|
||||
"map[${1:str}]${2:int} ${3:name}"
|
||||
],
|
||||
"description": "An empty map"
|
||||
},
|
||||
"or block": {
|
||||
"prefix": "orb",
|
||||
"body": [
|
||||
"or {",
|
||||
"\t${1:print(err)}",
|
||||
"\t${2:return}",
|
||||
"}"
|
||||
],
|
||||
"description": "Handle a failure: err is the message"
|
||||
},
|
||||
"for key, value": {
|
||||
"prefix": "forkv",
|
||||
"body": [
|
||||
"for ${1:key}, ${2:value} in ${3:map} {",
|
||||
"\t$0",
|
||||
"}"
|
||||
],
|
||||
"description": "Every key and value of a map (or index and element of an array)"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,12 +85,18 @@
|
|||
}
|
||||
},
|
||||
"function": {
|
||||
"match": "\\b(fn)\\s+([A-Za-z_][A-Za-z0-9_]*)",
|
||||
"match": "\\b(fn)\\s+(?:([A-Za-z_][A-Za-z0-9_]*)(\\.))?([A-Za-z_][A-Za-z0-9_]*)",
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "storage.type.function.finch"
|
||||
},
|
||||
"2": {
|
||||
"name": "entity.name.type.finch"
|
||||
},
|
||||
"3": {
|
||||
"name": "punctuation.accessor.finch"
|
||||
},
|
||||
"4": {
|
||||
"name": "entity.name.function.finch"
|
||||
}
|
||||
}
|
||||
|
|
@ -111,7 +117,7 @@
|
|||
},
|
||||
{
|
||||
"name": "keyword.control.finch",
|
||||
"match": "\\b(if|else|while|for|in|break|continue|return|defer)\\b"
|
||||
"match": "\\b(if|else|while|for|in|break|continue|return|defer|or|try)\\b"
|
||||
},
|
||||
{
|
||||
"name": "storage.type.function.finch",
|
||||
|
|
@ -126,11 +132,15 @@
|
|||
"match": "\\b(true|false|null)\\b"
|
||||
},
|
||||
{
|
||||
"name": "storage.type.primitive.finch",
|
||||
"match": "\\b(int|float|bool|char|str|ptr|i8|i16|i32|i64|u8|u16|u32|u64|f32|f64)\\b"
|
||||
"name": "variable.language.self.finch",
|
||||
"match": "\\bself\\b"
|
||||
},
|
||||
{
|
||||
"match": "\\b(print|input|read_file|write_file|file_exists|delete_file|shell|exit|addr|new|free)\\s*(?=\\()",
|
||||
"name": "storage.type.primitive.finch",
|
||||
"match": "\\b(int|float|bool|char|str|ptr|map|i8|i16|i32|i64|u8|u16|u32|u64|f32|f64)\\b"
|
||||
},
|
||||
{
|
||||
"match": "\\b(print|input|read_file|write_file|file_exists|delete_file|shell|exit|addr|new|free|error)\\s*(?=\\()",
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "support.function.builtin.finch"
|
||||
|
|
@ -238,4 +248,4 @@
|
|||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,12 @@ const code = [
|
|||
' p := Point(x: 1)',
|
||||
' return a + p.x',
|
||||
'}',
|
||||
'fn Point.move(int dx) -> int! {',
|
||||
' map[str]int m',
|
||||
' n := try parse(s) or 0',
|
||||
' self.x += dx',
|
||||
' return error("no")',
|
||||
'}',
|
||||
];
|
||||
const expect = [ // [line, token text, scope that must be present]
|
||||
[0, 'import', 'keyword.control.import'], [0, '"stdio.h"', 'string.quoted.double'],
|
||||
|
|
@ -32,6 +38,11 @@ const expect = [ // [line, token text, scope that must be present]
|
|||
[7, 'c', 'string.quoted.single'], [7, '3.5', 'constant.numeric.float'], [7, 'true', 'constant.language'], [7, 'null', 'constant.language'],
|
||||
[8, 'Point', 'entity.name.type'],
|
||||
[9, 'return', 'keyword.control'],
|
||||
[11, 'Point', 'entity.name.type'], [11, 'move', 'entity.name.function'], [11, '!', 'keyword.operator'],
|
||||
[12, 'map', 'storage.type.primitive'],
|
||||
[13, 'try', 'keyword.control'], [13, 'or', 'keyword.control'],
|
||||
[14, 'self', 'variable.language.self'],
|
||||
[15, 'error', 'support.function.builtin'],
|
||||
];
|
||||
registry.loadGrammar('source.finch').then((g) => {
|
||||
let state = vsctm.INITIAL, toks = [];
|
||||
|
|
|
|||
Loading…
Reference in a new issue