aboutsummaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorRyo Nihei <nihei.dev@gmail.com>2021-05-04 00:44:47 +0900
committerRyo Nihei <nihei.dev@gmail.com>2021-05-04 00:44:47 +0900
commit8a37dfeb49435f36a791fa92a6618afd7f3584f9 (patch)
tree99ba1262b0c01f7c8d2fa5fbfe92c7eff3314d82 /spec
parentGenerate an invalid token from incompleted input. (diff)
downloadtre-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.go75
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"`
+}