From 6e41aa36ac9d5c0f61f3fa3d65b5ce07a2dffe92 Mon Sep 17 00:00:00 2001 From: James Diacono Date: Sun, 17 Dec 2023 17:46:52 +1100 Subject: [PATCH] uFork assembly syntax --- tools/asm_sublime_linter.py | 11 +- tools/uforkasm/README.md | 12 ++ tools/uforkasm/syntax_test.asm | 82 ++++++++++++ tools/uforkasm/uforkasm.sublime-settings | 4 + tools/uforkasm/uforkasm.sublime-syntax | 152 +++++++++++++++++++++++ 5 files changed, 255 insertions(+), 6 deletions(-) create mode 100644 tools/uforkasm/README.md create mode 100644 tools/uforkasm/syntax_test.asm create mode 100644 tools/uforkasm/uforkasm.sublime-settings create mode 100644 tools/uforkasm/uforkasm.sublime-syntax diff --git a/tools/asm_sublime_linter.py b/tools/asm_sublime_linter.py index b1c25c2d..7785d2ed 100644 --- a/tools/asm_sublime_linter.py +++ b/tools/asm_sublime_linter.py @@ -1,18 +1,17 @@ # A SublimeLinter plugin for uFork assembly. -# Only Sublime views whose syntax type is set to assembly will be linted. This -# may require the installation of a syntax package such as -# https://github.com/dougmasten/sublime-assembly-6809. +# Only Sublime views whose syntax type is set to uFork Assembly will be linted. +# This requires installation of the uFork Assembly syntax package, ./uforkasm. # To install this plugin, first install the SublimeLinter package. Create a -# directory in Sublime's Packages directory called "SublimeLinter-asm". +# directory in Sublime's Packages directory called "SublimeLinter-uforkasm". # The location of the Packages directory depends on your operating system: # MacOS: ~/Library/Application Support/Sublime Text/Packages # Windows: %AppData%\Sublime Text\Packages # Linux: ~/.config/sublime-text/Packages -# Soft link this file into the "SublimeLinter-asm" directory, and +# Soft link this file into the "SublimeLinter-uforkasm" directory, and # run "Reload SublimeLinter and its Plugins" from the command palette. from os import path @@ -32,4 +31,4 @@ class asm(Linter): regex = r'^(?P\d+):(?P\d+) (?P.*)' multiline = False error_stream = STREAM_STDOUT - defaults = {'selector': 'source.asm, source.mc6809'} + defaults = {'selector': 'source.uforkasm'} diff --git a/tools/uforkasm/README.md b/tools/uforkasm/README.md new file mode 100644 index 00000000..3618c908 --- /dev/null +++ b/tools/uforkasm/README.md @@ -0,0 +1,12 @@ +# uFork Assembly Syntax Highlighting for Sublime Text + +A [Sublime Text](https://www.sublimetext.com/) syntax highlighting package for +the [uFork Assembly language](https://github.com/organix/uFork/blob/main/docs/asm.md). + +To install, symlink this directory into your Sublime Text "Packages" directory +with the name "uforkasm". + +To run the tests: +- install the "UnitTesting" package via Package Control +- open the syntax_test.asm file +- search for and run the "Build With: Syntax Tests" command diff --git a/tools/uforkasm/syntax_test.asm b/tools/uforkasm/syntax_test.asm new file mode 100644 index 00000000..298070a6 --- /dev/null +++ b/tools/uforkasm/syntax_test.asm @@ -0,0 +1,82 @@ +# SYNTAX TEST "Packages/uforkasm/uforkasm.sublime-syntax" +# <- source.uforkasm + +; My test module +# <- punctuation.definition.comment.uforkasm +# ^^^^^^^^^^^^^^ comment.line.uforkasm + +.import +# <- support.function.directive.uforkasm + std: "./std.asm" +# ^^^ entity.name.namespace.uforkasm +# ^ punctuation.separator.uforkasm +# ^^^^^^^^^^^ string.quoted.double.uforkasm +# ^ punctuation.definition.string.begin.uforkasm +# ^ punctuation.definition.string.end.uforkasm + ; comment +# ^^^^^^^^^ comment.line.uforkasm + lib: "../lib.asm" ; comment +# ^^^^^^^^^ comment.line.uforkasm + +decimal: +# <- entity.name.type.constant.uforkasm +# ^ punctuation.separator.uforkasm + ref 0 +literal: + ref 'u' +# ^^^ constant.numeric.integer.other.uforkasm +emoji: + ref '😀' +# ^^^ constant.numeric.integer.other.uforkasm +escape: + ref '\n' +# ^^^^ constant.numeric.integer.other.uforkasm +quad: + quad_2 2#0011011 16#DEAF123 +# ^^^^^^ storage.type.uforkasm +# ^^^^^^^^^ constant.numeric.integer.uforkasm +# ^ punctuation.separator.uforkasm +# ^^^^^^^^^^ constant.numeric.integer.uforkasm + +beh: +# <- entity.name.type.constant.uforkasm +# ^ punctuation.separator.uforkasm +race_beh: ; (requestors throttle) <- request +# <- entity.name.type.constant.uforkasm +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ comment.line.uforkasm + +; The work of handling the request is deferred to a dedicated "runner" actor, +; freeing up the race requestor to accept additional requests. +# <- comment.line.uforkasm + + msg -2 ; value +# ^^^ keyword.operator.word.uforkasm +# ^^ constant.numeric.integer.uforkasm +# ^^^^^^^ comment.line.uforkasm + + push #nil ; value callback queue running=() +# ^^^^ constant.language.uforkasm + push runner_beh ; value callback queue running runner_beh +# ^^^^^^^^^^ entity.name.type.constant.uforkasm + typeq #actor_t ; runner cap?(to_cancel) +# ^^^^^^^^ constant.language.uforkasm + if_not std.commit ; runner +# ^^^ entity.name.namespace.uforkasm +# ^ punctuation.accessor.uforkasm +# ^^^^^^ variable.other.member.uforkasm + cmp eq #t +# ^^ constant.language.uforkasm + dict has +# ^^^^ keyword.operator.word.uforkasm +# ^^^ keyword.operator.word.uforkasm + ref std.commit + + ; Provide a cancel capability. +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ comment.line.uforkasm + +.export +# <- support.function.directive.uforkasm + beh +# ^^^ entity.name.type.constant.uforkasm + quad +# ^^^^ entity.name.type.constant.uforkasm diff --git a/tools/uforkasm/uforkasm.sublime-settings b/tools/uforkasm/uforkasm.sublime-settings new file mode 100644 index 00000000..26d12d91 --- /dev/null +++ b/tools/uforkasm/uforkasm.sublime-settings @@ -0,0 +1,4 @@ +{ + "extensions": ["asm"], + "tab_size": 4, +} diff --git a/tools/uforkasm/uforkasm.sublime-syntax b/tools/uforkasm/uforkasm.sublime-syntax new file mode 100644 index 00000000..bfa33eb6 --- /dev/null +++ b/tools/uforkasm/uforkasm.sublime-syntax @@ -0,0 +1,152 @@ +%YAML 1.2 +--- +# http://www.sublimetext.com/docs/3/syntax.html +# http://www.sublimetext.com/docs/3/scope_naming.html + +name: uFork Assembly +file_extensions: [asm] +scope: source.uforkasm +version: 2 + +contexts: + main: + - include: comments + - match: ^\.import\b + scope: support.function.directive.uforkasm + set: imports + - match: '^(\w+)(:)' + captures: + 1: entity.name.type.constant.uforkasm + 2: punctuation.separator.uforkasm + set: definitions + comments: + - match: (\s*)((;).*)$ + captures: + 2: comment.line.uforkasm + 3: punctuation.definition.comment.uforkasm + +# Imports + + imports: + - include: comments + - match: '^\s+(\w+)(:)' + captures: + 1: entity.name.namespace.uforkasm + 2: punctuation.separator.uforkasm + push: import + - match: '^(\w+)(:)' + captures: + 1: entity.name.type.constant.uforkasm + 2: punctuation.separator.uforkasm + set: definitions + import: + - include: comments + - match: '"' + scope: punctuation.definition.string.begin.uforkasm + push: import_specifier + - match: '\n|\r\n?' + pop: true + import_specifier: + - meta_scope: string.quoted.double.uforkasm + - match: '"' + scope: punctuation.definition.string.end.uforkasm + pop: true + +# Definitions + + definitions: + - include: comments + - match: '^(\w+)(:)' + captures: + 1: entity.name.type.constant.uforkasm + 2: punctuation.separator.uforkasm + - match: '^\s+(ref|jump|pair_t|dict_t|type_t|quad_1|quad_2|quad_3|quad_4)\b' + captures: + 1: storage.type.uforkasm + push: operands + - match: '^\s+(if|if_not)\b' + captures: + 1: support.function.conditional.uforkasm + push: operands + - match: '^\s+(dict)\s+(has|get|add|set|del)\b' + captures: + 1: keyword.operator.word.uforkasm + 2: keyword.operator.word.uforkasm + push: operands + - match: '^\s+(alu)\s+(not|and|or|xor|add|sub|mul|div|lsl|lsr|asr|rol|ror)\b' + captures: + 1: keyword.operator.word.uforkasm + 2: keyword.operator.word.uforkasm + push: operands + - match: '^\s+(cmp)\s+(eq|ge|gt|lt|le|ne)\b' + captures: + 1: keyword.operator.word.uforkasm + 2: keyword.operator.word.uforkasm + push: operands + - match: '^\s+(my)\s+(self|beh|state)\b' + captures: + 1: keyword.operator.word.uforkasm + 2: keyword.operator.word.uforkasm + push: operands + - match: '^\s+(deque)\s+(new|empty|push|pop|put|pull|len)\b' + captures: + 1: keyword.operator.word.uforkasm + 2: keyword.operator.word.uforkasm + push: operands + - match: '^\s+(sponsor)\s+(new|memory|events|cycles|reclaim|start|stop)\b' + captures: + 1: keyword.operator.word.uforkasm + 2: keyword.operator.word.uforkasm + push: operands + - match: '^\s+(end)\s+(abort|stop|commit)\b' + captures: + 1: keyword.operator.word.uforkasm + 2: keyword.operator.word.uforkasm + push: operands + - match: '^\s+(assert|beh|debug|drop|dup|eq|msg|new|nth|pair|part|pick|push|quad|roll|send|signal|state|typeq)\b' + captures: + 1: keyword.operator.word.uforkasm + push: operands + - match: '^\.export\b' + scope: support.function.directive.uforkasm + set: exports + operands: + - include: comments + - match: ' +' + push: operand + - match: '\n|\r\n?' + pop: true + operand: + - match: '#(t|f|\?|nil|unit|literal_t|fixnum_t|type_t|pair_t|dict_t|instr_t|actor_t)' + scope: constant.language.uforkasm + pop: true + - match: '\d+(#)[0-9A-Za-z]+' + scope: constant.numeric.integer.uforkasm + captures: + 1: punctuation.separator.uforkasm + pop: true + - match: '-?\d+' + scope: constant.numeric.integer.uforkasm + pop: true + - match: \'(\\(b|t|n|r|\'|\\)|.)\' + scope: constant.numeric.integer.other.uforkasm + pop: true + - match: '(\w+)(\.)(\w+)' + captures: + 1: entity.name.namespace.uforkasm + 2: punctuation.accessor.uforkasm + 3: variable.other.member.uforkasm + pop: true + - match: '\w+' + scope: entity.name.type.constant.uforkasm + pop: true + - match: '\n|\r\n?' + pop: true + + # Exports + + exports: + - include: comments + - match: '^\s+(\w+)\n' + captures: + 1: entity.name.type.constant.uforkasm