pmacs3/mode/forth.py

122 lines
6.2 KiB
Python

import time
import tab
from mode import Fundamental
from lex import Grammar, PatternRule, RegionRule, NocasePatternRule
from lex import NocaseRegionRule, NocasePatternMatchRule
from mode.python import StringGrammar2
from mode.pipe import Pipe
from method.shell import Interact
class DataGrammar(Grammar): rules = [PatternRule('data', r'[^)]+')]
class LineGrammar(Grammar): rules = [PatternRule('data', r'.+')]
class StringGrammar3(Grammar): rules = [PatternRule('data', r'[^)]+')]
class ForthGrammar(Grammar):
rules = [
PatternRule('comment', r"\\(?: .*)?\n$"),
RegionRule('comment', r'\((?= |\n)', DataGrammar, r'\)'),
NocaseRegionRule('comment', r'0 \[if\]', DataGrammar, r'\[(?:endif|then)\]'),
RegionRule('string', r'[.cs]" ', StringGrammar2, r'"'),
RegionRule('string', r'[.s]\\" ', StringGrammar2, r'"'),
RegionRule('string', r'\.\( ', StringGrammar3, r'\)'),
# builtin
NocasePatternRule('builtin', r'(?:true|false|on|off)(?= |\n|$)'),
# mathn
NocasePatternRule('keyword', r'(?:\+|-|\*/mod|\*/|\*|/mod|/|mod|negate|abs|min|max|and|or|xor|not|lshift|rshift|invert|2\*|2/|2\+|2-|1\+|1-|8\*|under\+|m\+|m\*/|m\*|um/mod|um\*|fm/mod|sm/rem|d\+|d-|dnegate|dabs|dmin|dmax|d2\*|d2/|f\+|f-|f\*\*|f\*|f/|fnegate|fabs|fmax|fmin|floor|fround|fsqrt|fexpm1|fexp|flnp1|fln|flog|falog|fsincos|fsinh|fsin|fcosh|fcos|ftanh|ftan|fasinh|fasin|facosh|facos|fatan2|fatanh|fatan|f2\*|f2/|1/f|f~rel|f~abs|f~|0<>|0<=|0<|0=|0>=|0>|<>|<=|<|>=|>|=|u<=|u<|u>=|u>|d0<=|d0<>|d0<|d0=|d0>=|d0>|d<=|d<>|d<|d=|d>=|d>|du<=|du<|du>=|du>|within|\?negate|\?dnegate)(?= |\n|$)'),
# stack
NocasePatternRule('keyword', r'(?:drop|nip|dup|over|tuck|swap|rot|-rot|\?dup|pick|roll|2drop|2nip|2dup|2over|2tuck|2swap|2rot|2-rot|3dup|4dup|5dup|3drop|4drop|5drop|8drop|4swap|4rot|4-rot|4tuck|8swap|8dup|>r|r>|r@|rdrop|2>r|2r>|2r@|2rdrop|4>r|4r>|4r@|4rdrop|fdrop|fnip|fdup|fover|ftuck|fswap|frot)(?= |\n|$)'),
# pointer
NocasePatternRule('keyword', r'(?:forthsp|sp@|sp!|fp@|fp!|rp@|rp!|lp@|lp!)(?= |\n|$)'),
# address
NocasePatternRule('keyword', r'(?:@|!|\+!|c@|c!|2@|2!|f@|f!|sf@|sf!|df@|df!|chars|char\+|cells|cell\+|cell|align|aligned|floats|float\+|float|faligned|falign|sfloats|sfloat\+|sfaligned|sfalign|dfloats|dfloat\+|dfaligned|dfalign|maxaligned|maxalign|cfaligned|cfalign|address-unit-bits|allot|allocate|here|move|erase|cmove>|cmove|fill|blank)(?= |\n|$)'),
# conditional (*)
NocasePatternRule('builtin', r'(?:if|else|endif|then|case|of|endof|endcase|\?dup-if|\?dup-0=-if|ahead|cs-pick|cs-roll|catch|throw|within)(?= |\n|$)'),
# iter (*)
NocasePatternRule('builtin', r'(?:begin|while|repeat|until|again|\?do|loop|i|j|k|\+do|u\+do|u-do|-do|do|\+loop|-loop|unloop|leave|\?leave|exit|done|for|next)(?= |\n|$)'),
# define
NocasePatternRule('builtin', r'(?:constant|2constant|fconstant|variable|2variable|fvariable|create|user|to|defer|is|does>|immediate|compile-only|compile|restrict|interpret|postpone|execute|literal|create-interpret/compile|interpretation>|<interpretation|compilation>|<compilation|\]|lastxt|comp\'|postpone|find-name|name>int|name\?int|name>comp|name>string|state|c;|cvariable|,|2,|f,|c,|\[(?:ifdef|ifundef|then|endif|then|else|\?do|do|loop|\+loop|next|begin|until|again|while|repeat|comp\'|\'|compile)\])(?= |\n|$)'),
# assembly (*)
NocasePatternRule('builtin', r'(?:assembler|code|end-code|;code|flush-icache|c,)(?= |\n|$)'),
# xyz
NocasePatternMatchRule('x', r'(:)( +)([^ ]+)', r'delimiter', r'spaces', r'function'),
PatternRule('delimiter', r"[:;\[\]]"),
NocasePatternRule('number', r"'[a-z](?= |$)"),
NocasePatternRule('number', r'%?-?[0-1]+\.?(?= |$)'),
NocasePatternRule('number', r'[&#]?-?[0-9]+\.?(?= |$)'),
NocasePatternRule('number', r"(?:0x|\$)[0-9a-f]+\.?(?= |$)"),
NocasePatternRule('number', r'[+-]?[0-9]+\.?e?[+-][0-9]+(?= |$)'),
PatternRule('forth_word', r'[^ ]+'),
PatternRule('spaces', r' +'),
PatternRule('eol', r'\n'),
]
class GforthStart(Interact):
args = []
modename = 'forthpipe'
def _execute(self, w, **vargs):
Interact._execute(self, w, bname='*GForth*', cmd='gforth')
class GforthLoadFile(Interact):
args = []
modename = 'forthpipe'
def _execute(self, w, **vargs):
Interact._execute(self, w, bname='*GForth*', cmd='gforth')
b = w.application.get_buffer_by_name('*GForth*')
time.sleep(2.0)
path = w.buffer.path
b.pipe_write('s" ' + path + '" included\n')
br = RegionRule('banner', r'^Gforth \d+\.\d+\.\d+', LineGrammar, r"^Type `bye' to exit\n$")
class ForthPipeGrammar(Grammar):
rules = [br] + ForthGrammar.rules
class ForthPipe(Pipe):
name = 'forthpipe'
grammar = ForthPipeGrammar
dopen = {}
for s in ['if', 'case', 'of', '?dup-if', '?dup-0=-if', 'begin', 'while',
'until', '?do', 'for', 'code']:
dopen[s] = None
dclose = {}
for s in ['then', 'endif', 'again']:
dclose[s] = None
class ForthTabber(tab.StackTabber2):
open_tokens = {'builtin': dopen, 'delimiter': {':': ';'}}
close_tokens = {'builtin': dclose, 'delimiter': set([';'])}
continue_tokens = {'nomatch': set()}
fixed_indent = True
def is_base(self, y):
return y == 0
def _is_indent(self, t):
return t.name == 'spaces'
def _is_ignored(self, t):
return t.fqname() in ('spaces', 'eol', 'comment', 'comment.start',
'comment.data', 'comment.null', 'comment.end')
def _handle_other_token(self, y, tokens, start, end, i, t):
tab.StackTabber2._handle_other_token(self, y, tokens, start, end, i, t)
if t.match('builtin', 'else'):
if len(self.stack) > 1:
self.curr_level = self.stack[-2].level
else:
self.curr_level = 0
class Forth(Fundamental):
name = 'FORTH'
extensions = ['.fs', '.fi', '.fb']
grammar = ForthGrammar
commentc = '\\ '
actions = [GforthStart, GforthLoadFile]
tabbercls = ForthTabber
colors = {
'forth_word': ('yellow', 'default', 'bold'),
}
def install(*args):
Forth.install(*args)
ForthPipe.install(*args)