diff options
author | Ryo Nihei <nihei.dev@gmail.com> | 2021-05-04 00:44:47 +0900 |
---|---|---|
committer | Ryo Nihei <nihei.dev@gmail.com> | 2021-05-04 00:44:47 +0900 |
commit | 8a37dfeb49435f36a791fa92a6618afd7f3584f9 (patch) | |
tree | 99ba1262b0c01f7c8d2fa5fbfe92c7eff3314d82 /spec | |
parent | Generate an invalid token from incompleted input. (diff) | |
download | tre-8a37dfeb49435f36a791fa92a6618afd7f3584f9.tar.gz tre-8a37dfeb49435f36a791fa92a6618afd7f3584f9.tar.xz |
Add lex mode
lex mode is a feature that separates transition tables per each mode.
The lexer starts from an initial state indicated by `initial_state` field and
transitions between modes according to `push` and `pop` fields.
The initial state will always be `default`.
Currently, maleeni doesn't provide the ability to change the initial state.
You can specify the modes of each lex entry using `modes` field.
When the mode isn't indicated explicitly, the entries have `default` mode.
Diffstat (limited to 'spec')
-rw-r--r-- | spec/spec.go | 75 |
1 files changed, 72 insertions, 3 deletions
diff --git a/spec/spec.go b/spec/spec.go index 0f9b484..e2291e9 100644 --- a/spec/spec.go +++ b/spec/spec.go @@ -3,6 +3,7 @@ package spec import ( "fmt" "regexp" + "strconv" "strings" ) @@ -37,9 +38,61 @@ func (p LexPattern) validate() error { return nil } +const lexModePattern = "[A-Za-z_][0-9A-Za-z_]*" + +var lexModeRE = regexp.MustCompile(lexKindPattern) + +type LexModeName string + +const ( + LexModeNameNil = LexModeName("") + LexModeNameDefault = LexModeName("default") +) + +func (m LexModeName) String() string { + return string(m) +} + +func (m LexModeName) validate() error { + if m.isNil() || !lexModeRE.Match([]byte(m)) { + return fmt.Errorf("mode must be %v", lexModePattern) + } + return nil +} + +func (m LexModeName) isNil() bool { + return m == LexModeNameNil +} + +type LexModeNum int + +const ( + LexModeNumNil = LexModeNum(0) + LexModeNumDefault = LexModeNum(1) +) + +func (n LexModeNum) String() string { + return strconv.Itoa(int(n)) +} + +func (n LexModeNum) Int() int { + return int(n) +} + +func (n LexModeNum) Succ() LexModeNum { + return n + 1 +} + +func (n LexModeNum) IsNil() bool { + return n == LexModeNumNil +} + type LexEntry struct { - Kind LexKind `json:"kind"` - Pattern LexPattern `json:"pattern"` + Kind LexKind `json:"kind"` + Pattern LexPattern `json:"pattern"` + Modes []LexModeName `json:"modes"` + Push LexModeName `json:"push"` + Pop bool `json:"pop"` } func (e *LexEntry) validate() error { @@ -51,6 +104,14 @@ func (e *LexEntry) validate() error { if err != nil { return err } + if len(e.Modes) > 0 { + for _, mode := range e.Modes { + err = mode.validate() + if err != nil { + return err + } + } + } return nil } @@ -97,7 +158,15 @@ type TransitionTable struct { Transition [][]int `json:"transition"` } -type CompiledLexSpec struct { +type CompiledLexModeSpec struct { Kinds []LexKind `json:"kinds"` + Push []LexModeNum `json:"push"` + Pop []int `json:"pop"` DFA *TransitionTable `json:"dfa"` } + +type CompiledLexSpec struct { + InitialMode LexModeNum `json:"initial_mode"` + Modes []LexModeName `json:"modes"` + Specs []*CompiledLexModeSpec `json:"specs"` +} |