package subex import ( "fmt" "main/walk" ) // A node in the AST of a subex type SubexAST interface { compileWith(next SubexState) SubexState } // Process the first subex, then the second, splitting the input text in two type SubexASTConcat struct { first, second SubexAST } func (ast SubexASTConcat) compileWith(next SubexState) SubexState { return ast.first.compileWith(ast.second.compileWith(next)) } func (ast SubexASTConcat) String() string { return fmt.Sprintf("(%v)(%v)", ast.first, ast.second) } // Processing a subex and storing the output in a slot instead of outputting it type SubexASTStore struct { match SubexAST slot rune } func (ast SubexASTStore) compileWith(next SubexState) SubexState { return &SubexStoreState { match: ast.match.compileWith(&SubexNoneState{}), slot: ast.slot, next: next, } } func (ast SubexASTStore) String() string { return fmt.Sprintf("$%c(%v)", ast.slot, ast.match) } // Try to run the first subex, if it fails then backtrack and use the second type SubexASTOr struct { first, second SubexAST } func (ast SubexASTOr) compileWith(next SubexState) SubexState { return &SubexGroupState { ast.first.compileWith(next), ast.second.compileWith(next), } } // Run the content subex as many times as possible as the input is read in type SubexASTMaximise struct { content SubexAST } func (ast SubexASTMaximise) compileWith(next SubexState) SubexState { state := &SubexGroupState { nil, next, } state.first = ast.content.compileWith(state) return state } func (ast SubexASTMaximise) String() string { return fmt.Sprintf("(%v)*", ast.content) } // Run the content subex as few times as possible as the input is read in type SubexASTMinimise struct { content SubexAST } func (ast SubexASTMinimise) compileWith(next SubexState) SubexState { state := &SubexGroupState { next, nil, } state.second = ast.content.compileWith(state) return state } func (ast SubexASTMinimise) String() string { return fmt.Sprintf("(%v)-", ast.content) } // Run the subex as many times as possible but at least min times and at most max times type SubexASTRepeat struct { content SubexAST min, max int } func (ast SubexASTRepeat) compileWith(next SubexState) SubexState { for i := ast.min; i < ast.max; i += 1 { next = &SubexGroupState { ast.content.compileWith(next), next, } } for i := 0; i < ast.min; i += 1 { next = ast.content.compileWith(next) } return next } // Read in a single specific Atom and output it unchanged type SubexASTCopyAtom struct { atom walk.Atom } func (ast SubexASTCopyAtom) compileWith(next SubexState) SubexState { return &SubexCopyAtomState{ atom: ast.atom, next: next, } } // Read in any single Atom and output it unchanged type SubexASTCopyAny struct {} func (ast SubexASTCopyAny) compileWith(next SubexState) SubexState { return &SubexCopyAnyState{next} } func (ast SubexASTCopyAny) String() string { return "." } // Output a series of Atoms without reading anything from input type SubexASTOutput struct { replacement []OutputContent } func (ast SubexASTOutput) compileWith(next SubexState) SubexState { return &SubexOutputState{ content: ast.replacement, next: next, } } // Try to use a subex but just skip over this if it doesn't match type SubexASTTry struct { content SubexAST } func (ast SubexASTTry) compileWith(next SubexState) SubexState { return &SubexGroupState { ast.content.compileWith(next), next, } } // Try to skip over this subex but use it should that not match type SubexASTMaybe struct { content SubexAST } func (ast SubexASTMaybe) compileWith(next SubexState) SubexState { return &SubexGroupState { next, ast.content.compileWith(next), } } // Read in a repeated subex separated by a delimiter. Greedy type SubexASTJoin struct { content, delimiter SubexAST } func (ast SubexASTJoin) compileWith(next SubexState) SubexState { afterContentState := &SubexGroupState { nil, next, } manyContentsState := ast.content.compileWith(afterContentState) afterContentState.first = ast.delimiter.compileWith(manyContentsState) return &SubexGroupState { manyContentsState, next, } } // Run each input Atom through a map to produce an output Atom // Atoms not in the map cause this to not match type SubexASTRange struct { parts map[walk.Atom]walk.Atom } func (ast SubexASTRange) compileWith(next SubexState) SubexState { return &SubexRangeState { parts: ast.parts, next: next, } }