mirror of
https://github.com/jorenchik/mdemory.git
synced 2026-03-22 00:26:21 +00:00
error handling and transformation improvements
Added vscode config for easy debug including all modules.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
25
memorybase/faulty.mdem
Normal file
25
memorybase/faulty.mdem
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- Another question? >
|
||||||
|
- Answer
|
||||||
|
- Answer
|
||||||
|
- Answer
|
||||||
|
- Answer
|
||||||
|
- Answer
|
||||||
|
|
||||||
|
|
||||||
|
oejcoewjic
|
||||||
|
|
||||||
|
- Question? >
|
||||||
|
- Answer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
fwefew
|
||||||
|
|
||||||
|
dwedew
|
||||||
|
dwe
|
||||||
|
|
||||||
|
|
||||||
|
dee
|
||||||
@@ -1,110 +1,42 @@
|
|||||||
|
- [cap_riga] 1 What is the capital of Latvia? >
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
- Riga
|
||||||
|
- [cap_riga] 2 What is the capital of Latvia? >
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
- Riga
|
||||||
|
- [cap_riga] 3 What is the capital of Latvia? >
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
- Riga
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
- [cap_riga] 4 What is the capital of Latvia? >
|
||||||
- Riga
|
- Riga
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
- [cap_riga] 5 What is the capital of Latvia? >
|
||||||
- Riga
|
- Riga
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
- [cap_riga] 6 What is the capital of Latvia? >
|
||||||
- Riga
|
- Riga
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
- [cap_riga] 7 What is the capital of Latvia? >
|
||||||
- Riga
|
- Riga
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
- [cap_riga] 8 What is the capital of Latvia? >
|
||||||
- Riga
|
- Riga
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
- [cap_riga] 9 What is the capital of Latvia? >
|
||||||
- Riga
|
- Riga
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
- [cap_riga] 10 What is the capital of Latvia? >
|
||||||
- Riga
|
- Riga
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
- [cap_riga] 11 What is the capital of Latvia? >
|
||||||
- Riga
|
- Riga
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
- [cap_riga] 12 What is the capital of Latvia? >
|
||||||
- Riga
|
- Riga
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
- [cap_riga] 13 What is the capital of Latvia? >
|
||||||
- Riga
|
- Riga
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
- [cap_riga] 14 What is the capital of Latvia? >
|
||||||
- Riga
|
- Riga
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
- [cap_riga] 15 What is the capital of Latvia? >
|
||||||
- Riga
|
- Riga
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
- [cap_riga] 16 What is the capital of Latvia? >
|
||||||
- Riga
|
- Riga
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
- [cap_riga] 17 What is the capital of Latvia? >
|
||||||
- Riga
|
- Riga
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
- [cap_riga] 18 What is the capital of Latvia? >
|
||||||
- Riga
|
- Riga
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
- [cap_riga] 19 What is the capital of Latvia? >
|
||||||
- Riga
|
- Riga
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
- [cap_riga] 20 What is the capital of Latvia? >
|
||||||
- Riga
|
- Riga
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
- [cap_riga] 21 What is the capital of Latvia? >
|
||||||
- Riga
|
- Riga
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
|
||||||
- [cap_riga] What is the capital of Latvia? >
|
|
||||||
- Riga
|
|
||||||
|
|
||||||
|
|||||||
26
src/.vscode/launch.json
vendored
Normal file
26
src/.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Launch Package",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "auto",
|
||||||
|
"program": "${fileDirname}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Debug with Build Flags",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "debug",
|
||||||
|
"program": "${workspaceFolder}/mdemory-app-qt/main.go",
|
||||||
|
// "buildFlags": "-gcflags='all=-N -l'",
|
||||||
|
"args": [],
|
||||||
|
"env": {},
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,14 +1,13 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
||||||
"github.com/jorenchik/mdemory/src/compiler/lexer"
|
"github.com/jorenchik/mdemory/src/compiler/lexer"
|
||||||
"github.com/jorenchik/mdemory/src/compiler/parser"
|
"github.com/jorenchik/mdemory/src/compiler/parser"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Compile(fileContents string) ([]parser.Question, error) {
|
func Compile(fileContents string) ([]parser.Question, error) {
|
||||||
tokens, err := lexer.TokenizeMdem([]rune(fileContents))
|
tokens, err := lexer.TokenizeMdem([]rune(fileContents))
|
||||||
if err != nil {
|
if (err != nil) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
questions, err := parser.ParseQuestions(tokens)
|
questions, err := parser.ParseQuestions(tokens)
|
||||||
|
|||||||
15
src/compiler/comperror/comperror.go
Normal file
15
src/compiler/comperror/comperror.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package comperror
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PositionErr struct {
|
||||||
|
Message string
|
||||||
|
Row int32
|
||||||
|
Column int32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e PositionErr) Error() string {
|
||||||
|
return fmt.Sprintf("%d:%d - %s", e.Row, e.Column, e.Message)
|
||||||
|
}
|
||||||
@@ -3,6 +3,8 @@ package lexer
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/jorenchik/mdemory/src/compiler/comperror"
|
||||||
)
|
)
|
||||||
|
|
||||||
var buffer []rune
|
var buffer []rune
|
||||||
@@ -10,7 +12,8 @@ var row int32
|
|||||||
var column int32
|
var column int32
|
||||||
var previousRow int32
|
var previousRow int32
|
||||||
var previousColumn int32
|
var previousColumn int32
|
||||||
var textStarted bool
|
var textStarted bool = false
|
||||||
|
var identifierStarted bool = false
|
||||||
|
|
||||||
type TokenType int
|
type TokenType int
|
||||||
const (
|
const (
|
||||||
@@ -91,7 +94,7 @@ func makeTokenWithTokenBuffer(
|
|||||||
buffer = []rune{}
|
buffer = []rune{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TokenizeMdem(fileRunes []rune) ( []Token, error ) {
|
func TokenizeMdem(fileRunes []rune) ([]Token, error) {
|
||||||
tokens = []Token{}
|
tokens = []Token{}
|
||||||
buffer = []rune{}
|
buffer = []rune{}
|
||||||
row = 1
|
row = 1
|
||||||
@@ -104,7 +107,6 @@ func TokenizeMdem(fileRunes []rune) ( []Token, error ) {
|
|||||||
return []Token{}, nil
|
return []Token{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for i := 0; i < len(fileRunes); i++ {
|
for i := 0; i < len(fileRunes); i++ {
|
||||||
c := fileRunes[i]
|
c := fileRunes[i]
|
||||||
|
|
||||||
@@ -134,11 +136,21 @@ func TokenizeMdem(fileRunes []rune) ( []Token, error ) {
|
|||||||
previousRow = row
|
previousRow = row
|
||||||
previousColumn = column
|
previousColumn = column
|
||||||
textStarted = false
|
textStarted = false
|
||||||
|
identifierStarted = true
|
||||||
case ']':
|
case ']':
|
||||||
|
if !identifierStarted {
|
||||||
|
return []Token{}, comperror.PositionErr{
|
||||||
|
Message: "Cannot end identifier if it is not started",
|
||||||
|
Row: row,
|
||||||
|
Column: column,
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
makeTokenWithTokenBuffer(IdentifierEnd, 1, Identifier)
|
makeTokenWithTokenBuffer(IdentifierEnd, 1, Identifier)
|
||||||
previousRow = row
|
previousRow = row
|
||||||
previousColumn = column
|
previousColumn = column
|
||||||
textStarted = false
|
textStarted = false
|
||||||
|
identifierStarted = false
|
||||||
case '#':
|
case '#':
|
||||||
makeTokenWithTokenBuffer(SectionIdentifierStart, 1, TextFragment)
|
makeTokenWithTokenBuffer(SectionIdentifierStart, 1, TextFragment)
|
||||||
previousRow = row
|
previousRow = row
|
||||||
@@ -187,17 +199,17 @@ func TokenizeMdem(fileRunes []rune) ( []Token, error ) {
|
|||||||
|
|
||||||
func ToString (ttype *TokenType) string {
|
func ToString (ttype *TokenType) string {
|
||||||
switch *ttype {
|
switch *ttype {
|
||||||
case TextFragment: return "TextFragment"
|
case TextFragment: return "text fragment"
|
||||||
case QuestionEnd: return "QuestionEnd"
|
case QuestionEnd: return "question end symbol"
|
||||||
case ElementDashStart: return "ElementDashStart"
|
case ElementDashStart: return "dash element start"
|
||||||
case ElementPlusStart: return "ElementPlusStart"
|
case ElementPlusStart: return "plus element start"
|
||||||
case Identifier: return "Identifier"
|
case Identifier: return "identifier"
|
||||||
case IdentifierStart: return "IdentifierStart"
|
case IdentifierStart: return "start of identifier"
|
||||||
case IdentifierEnd: return "IdentifierEnd"
|
case IdentifierEnd: return "end of identifier"
|
||||||
case SectionIdentifierStart: return "SectionIdentifierStart"
|
case SectionIdentifierStart: return "identifier"
|
||||||
case SectionStart: return "SectionStart"
|
case SectionStart: return "start of a section"
|
||||||
case SectionEnd: return "SectionEnd"
|
case SectionEnd: return "end of a section"
|
||||||
case EOF: return "EndOfFile"
|
case EOF: return "end of a file"
|
||||||
default: return "NOT_RECOGNIZED"
|
default: return "unrecognized token"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/jorenchik/mdemory/src/compiler/comperror"
|
||||||
"github.com/jorenchik/mdemory/src/compiler/lexer"
|
"github.com/jorenchik/mdemory/src/compiler/lexer"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -67,16 +68,6 @@ type QuestionElement struct {
|
|||||||
|
|
||||||
var automata map[lexer.TokenType][]lexer.TokenType
|
var automata map[lexer.TokenType][]lexer.TokenType
|
||||||
|
|
||||||
type CompilerErr struct {
|
|
||||||
message string
|
|
||||||
row int32
|
|
||||||
column int32
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e CompilerErr) Error() string {
|
|
||||||
return fmt.Sprintf("%d:%d - %s", e.row, e.column, e.message)
|
|
||||||
}
|
|
||||||
|
|
||||||
func contains(s []lexer.TokenType, e lexer.TokenType) bool {
|
func contains(s []lexer.TokenType, e lexer.TokenType) bool {
|
||||||
for _, a := range s {
|
for _, a := range s {
|
||||||
if a == e {
|
if a == e {
|
||||||
@@ -140,20 +131,32 @@ func parserAutomata() map[lexer.TokenType][]lexer.TokenType {
|
|||||||
return automata
|
return automata
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func capitalize(str string) string {
|
||||||
|
if len(str) <= 0 {
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
firstCapital := strings.ToUpper(str[0:1])
|
||||||
|
if len(str) == 1 {
|
||||||
|
return firstCapital
|
||||||
|
} else {
|
||||||
|
return firstCapital + str[1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func ValidateGrammar(tokens []lexer.Token) error {
|
func ValidateGrammar(tokens []lexer.Token) error {
|
||||||
automata = parserAutomata()
|
automata = parserAutomata()
|
||||||
for i := 0; i < len(tokens) - 1; i++ {
|
for i := 0; i < len(tokens)-1; i++ {
|
||||||
token := tokens[i]
|
token := tokens[i]
|
||||||
nextToken := tokens[i+1]
|
nextToken := tokens[i+1]
|
||||||
if !contains(automata[token.TokenType], nextToken.TokenType) {
|
if !contains(automata[token.TokenType], nextToken.TokenType) {
|
||||||
return CompilerErr{
|
return comperror.PositionErr{
|
||||||
message: fmt.Sprintf(
|
Message: fmt.Sprintf(
|
||||||
"Token %s cannot precede %s\n",
|
"%s cannot precede %s",
|
||||||
lexer.ToString(&token.TokenType),
|
capitalize(lexer.ToString(&token.TokenType)),
|
||||||
lexer.ToString(&nextToken.TokenType),
|
lexer.ToString(&nextToken.TokenType),
|
||||||
),
|
),
|
||||||
row: token.Row,
|
Row: token.Row,
|
||||||
column: token.Column,
|
Column: token.Column,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -184,14 +187,14 @@ func ParseQuestions(tokens []lexer.Token) ([]Question, error) {
|
|||||||
var question string
|
var question string
|
||||||
var questionElements []QuestionElement
|
var questionElements []QuestionElement
|
||||||
|
|
||||||
if tokens[i + 1].TokenType == lexer.IdentifierStart {
|
if tokens[i+1].TokenType == lexer.IdentifierStart {
|
||||||
id = tokens[i + 2].Content
|
id = tokens[i+2].Content
|
||||||
question = tokens[i + 4].Content
|
question = tokens[i+4].Content
|
||||||
questionElements = []QuestionElement{}
|
questionElements = []QuestionElement{}
|
||||||
i += 6
|
i += 6
|
||||||
} else {
|
} else {
|
||||||
id = ""
|
id = ""
|
||||||
question = tokens[i + 1].Content
|
question = tokens[i+1].Content
|
||||||
questionElements = []QuestionElement{}
|
questionElements = []QuestionElement{}
|
||||||
i += 3
|
i += 3
|
||||||
}
|
}
|
||||||
@@ -202,29 +205,29 @@ func ParseQuestions(tokens []lexer.Token) ([]Question, error) {
|
|||||||
// - [identifier] a_question >
|
// - [identifier] a_question >
|
||||||
// - an_element
|
// - an_element
|
||||||
// terminate if we encounter a question.
|
// terminate if we encounter a question.
|
||||||
if i + 3 < len(tokens) &&
|
if i+3 < len(tokens) &&
|
||||||
tokens[i + 3].TokenType != lexer.EOF {
|
tokens[i+3].TokenType != lexer.EOF {
|
||||||
|
|
||||||
offset := 0
|
offset := 0
|
||||||
if tokens[i + 1].TokenType == lexer.IdentifierStart {
|
if tokens[i+1].TokenType == lexer.IdentifierStart {
|
||||||
offset = 5
|
offset = 5
|
||||||
} else {
|
} else {
|
||||||
offset = 2
|
offset = 2
|
||||||
}
|
}
|
||||||
if i + offset < len(tokens) &&
|
if i+offset < len(tokens) &&
|
||||||
tokens[i + offset].TokenType == lexer.QuestionEnd {
|
tokens[i+offset].TokenType == lexer.QuestionEnd {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if offset == 5 && tokens[i + 5].TokenType != lexer.QuestionEnd {
|
if offset == 5 && tokens[i+5].TokenType != lexer.QuestionEnd {
|
||||||
return nil, CompilerErr{
|
return nil, comperror.PositionErr{
|
||||||
message: "Cannot have an identifier here",
|
Message: "Cannot have an identifier here",
|
||||||
row: tokens[i].Row,
|
Row: tokens[i].Row,
|
||||||
column: tokens[i].Column,
|
Column: tokens[i].Column,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i + 2 >= len(tokens)) {
|
if i+2 >= len(tokens) {
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
questionElement := QuestionElement{}
|
questionElement := QuestionElement{}
|
||||||
if tokens[i].TokenType == lexer.ElementDashStart {
|
if tokens[i].TokenType == lexer.ElementDashStart {
|
||||||
@@ -232,7 +235,7 @@ func ParseQuestions(tokens []lexer.Token) ([]Question, error) {
|
|||||||
} else {
|
} else {
|
||||||
questionElement.isDash = false
|
questionElement.isDash = false
|
||||||
}
|
}
|
||||||
questionElement.content = tokens[i + 1].Content
|
questionElement.content = tokens[i+1].Content
|
||||||
questionElements = append(questionElements, questionElement)
|
questionElements = append(questionElements, questionElement)
|
||||||
i += 2
|
i += 2
|
||||||
}
|
}
|
||||||
@@ -271,7 +274,7 @@ func ParseQuestions(tokens []lexer.Token) ([]Question, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if tokens[i].TokenType == lexer.SectionIdentifierStart {
|
} else if tokens[i].TokenType == lexer.SectionIdentifierStart {
|
||||||
section = tokens[i + 1].Content
|
section = tokens[i+1].Content
|
||||||
i += 3
|
i += 3
|
||||||
if DEBUG {
|
if DEBUG {
|
||||||
fmt.Printf("Started section: %s\n", section)
|
fmt.Printf("Started section: %s\n", section)
|
||||||
@@ -288,10 +291,10 @@ func ParseQuestions(tokens []lexer.Token) ([]Question, error) {
|
|||||||
}
|
}
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
return nil, CompilerErr{
|
return nil, comperror.PositionErr{
|
||||||
message: "Unexpeced token: %s",
|
Message: "Unexpeced token",
|
||||||
row: tokens[i].Row,
|
Row: tokens[i].Row,
|
||||||
column: tokens[i].Column,
|
Column: tokens[i].Column,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,16 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
// iter: 1
|
|
||||||
// [1] 2 3 4 5 6 7
|
|
||||||
|
|
||||||
// 2
|
|
||||||
// press 4
|
|
||||||
// 1 2 3 [4] 5 6 7
|
|
||||||
// 4 (page num) - 2
|
|
||||||
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"strconv"
|
|
||||||
"math/rand"
|
|
||||||
|
|
||||||
"github.com/jorenchik/mdemory/src/compiler/api"
|
"github.com/jorenchik/mdemory/src/compiler/api"
|
||||||
|
"github.com/jorenchik/mdemory/src/compiler/comperror"
|
||||||
"github.com/jorenchik/mdemory/src/compiler/parser"
|
"github.com/jorenchik/mdemory/src/compiler/parser"
|
||||||
"github.com/therecipe/qt/core"
|
"github.com/therecipe/qt/core"
|
||||||
"github.com/therecipe/qt/widgets"
|
"github.com/therecipe/qt/widgets"
|
||||||
@@ -42,6 +35,12 @@ var questions [] parser.Question
|
|||||||
var paginationButtons []*widgets.QToolButton
|
var paginationButtons []*widgets.QToolButton
|
||||||
var paginationLabel *widgets.QLabel
|
var paginationLabel *widgets.QLabel
|
||||||
|
|
||||||
|
var errorBox *widgets.QWidget
|
||||||
|
var errorLabel *widgets.QLabel
|
||||||
|
|
||||||
|
|
||||||
|
var multispacePattern *regexp.Regexp = regexp.MustCompile(`\s\s+`)
|
||||||
|
|
||||||
// var currentPage = 0
|
// var currentPage = 0
|
||||||
var PER_PAGE = 10
|
var PER_PAGE = 10
|
||||||
var pages []Page
|
var pages []Page
|
||||||
@@ -156,13 +155,7 @@ func CreateMdem() *Mdem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func CreateMdems(questions *[]parser.Question) {
|
func CreateMdems(questions *[]parser.Question) {
|
||||||
if spacerInitialized {
|
|
||||||
hMdemScroll.RemoveItem(mdemSpacer)
|
hMdemScroll.RemoveItem(mdemSpacer)
|
||||||
} else {
|
|
||||||
mdemSpacer = widgets.NewQSpacerItem(
|
|
||||||
0, 0, widgets.QSizePolicy__Maximum, widgets.QSizePolicy__Minimum,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range mdems {
|
for i := range mdems {
|
||||||
if mdems[i].wMdem.IsVisible() {
|
if mdems[i].wMdem.IsVisible() {
|
||||||
@@ -179,6 +172,12 @@ func CreateMdems(questions *[]parser.Question) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// destroy widgets
|
// destroy widgets
|
||||||
|
transformAnswer := func(answer string) string {
|
||||||
|
answer = strings.ReplaceAll(answer, "\t", " ")
|
||||||
|
answer = strings.ReplaceAll(answer, "\n", " ")
|
||||||
|
answer = multispacePattern.ReplaceAllString(answer, ` `)
|
||||||
|
return answer
|
||||||
|
}
|
||||||
for i := range *questions {
|
for i := range *questions {
|
||||||
question := (*questions)[i]
|
question := (*questions)[i]
|
||||||
switch question.(type) {
|
switch question.(type) {
|
||||||
@@ -186,10 +185,10 @@ func CreateMdems(questions *[]parser.Question) {
|
|||||||
mdems[i].wFrontText.SetText(
|
mdems[i].wFrontText.SetText(
|
||||||
question.(parser.SingleAnswerQuestion).Question,
|
question.(parser.SingleAnswerQuestion).Question,
|
||||||
)
|
)
|
||||||
answer := strings.Trim(
|
answer := question.(parser.SingleAnswerQuestion).Answer
|
||||||
question.(parser.SingleAnswerQuestion).Answer, " \t\n",
|
answer = transformAnswer(answer)
|
||||||
)
|
answer = fmt.Sprintf("- %s", answer)
|
||||||
mdems[i].backLabels[0].SetText(fmt.Sprintf("- %s", answer))
|
mdems[i].backLabels[0].SetText(answer)
|
||||||
if mdems[i].wBack.IsVisible() {
|
if mdems[i].wBack.IsVisible() {
|
||||||
mdems[i].wBack.Hide()
|
mdems[i].wBack.Hide()
|
||||||
}
|
}
|
||||||
@@ -200,11 +199,13 @@ func CreateMdems(questions *[]parser.Question) {
|
|||||||
question.(parser.MultipleChoiceQuestion).Question,
|
question.(parser.MultipleChoiceQuestion).Question,
|
||||||
)
|
)
|
||||||
for k := range choices {
|
for k := range choices {
|
||||||
answer := strings.Trim(choices[k].Answer, " \t\n")
|
answer := choices[k].Answer
|
||||||
|
answer = transformAnswer(answer)
|
||||||
|
answer = fmt.Sprintf("- %s", answer)
|
||||||
if k < len(mdems[i].backLabels) {
|
if k < len(mdems[i].backLabels) {
|
||||||
mdems[i].backLabels[k].SetText(answer)
|
mdems[i].backLabels[k].SetText(answer)
|
||||||
} else {
|
} else {
|
||||||
label := widgets.NewQLabel2(fmt.Sprintf("- %s", answer), nil, 0)
|
label := widgets.NewQLabel2(answer, nil, 0)
|
||||||
mdems[i].backLabels = append(
|
mdems[i].backLabels = append(
|
||||||
mdems[i].backLabels,
|
mdems[i].backLabels,
|
||||||
label,
|
label,
|
||||||
@@ -219,15 +220,6 @@ func CreateMdems(questions *[]parser.Question) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !spacerInitialized {
|
|
||||||
mdemSpacer = widgets.NewQSpacerItem(
|
|
||||||
40,
|
|
||||||
40,
|
|
||||||
widgets.QSizePolicy__Minimum,
|
|
||||||
widgets.QSizePolicy__Expanding,
|
|
||||||
)
|
|
||||||
spacerInitialized = true
|
|
||||||
}
|
|
||||||
hMdemScroll.AddItem(mdemSpacer)
|
hMdemScroll.AddItem(mdemSpacer)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,6 +305,9 @@ func OpenModelFile(
|
|||||||
if model.IsDir(index) {
|
if model.IsDir(index) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if errorBox.IsVisible() {
|
||||||
|
errorBox.Hide()
|
||||||
|
}
|
||||||
filePath := model.FilePath(index)
|
filePath := model.FilePath(index)
|
||||||
fileContents, err := os.ReadFile(filePath)
|
fileContents, err := os.ReadFile(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -329,13 +324,25 @@ func OpenModelFile(
|
|||||||
start := time.Now().UnixMicro()
|
start := time.Now().UnixMicro()
|
||||||
questions, err = api.Compile(string(fileContents))
|
questions, err = api.Compile(string(fileContents))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
widgets.QMessageBox_Critical(
|
var errText string
|
||||||
nil,
|
switch err.(type) {
|
||||||
"Compilation error",
|
case comperror.PositionErr:
|
||||||
err.Error(),
|
errText = fmt.Sprintf(
|
||||||
widgets.QMessageBox__Ok,
|
"%s on line %d, column %d",
|
||||||
widgets.QMessageBox__Ok,
|
err.(comperror.PositionErr).Message,
|
||||||
|
err.(comperror.PositionErr).Row,
|
||||||
|
err.(comperror.PositionErr).Column,
|
||||||
)
|
)
|
||||||
|
default:
|
||||||
|
errText = err.Error()
|
||||||
|
}
|
||||||
|
errorLabel.SetText(errText)
|
||||||
|
errorBox.Show()
|
||||||
|
for i := range(mdems) {
|
||||||
|
if mdems[i].wMdem.IsVisible() {
|
||||||
|
mdems[i].wMdem.Hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
duration := float32(time.Now().UnixMicro()-start) / 1000
|
duration := float32(time.Now().UnixMicro()-start) / 1000
|
||||||
@@ -420,6 +427,24 @@ func main() {
|
|||||||
mdemScroll.SetWidgetResizable(true)
|
mdemScroll.SetWidgetResizable(true)
|
||||||
mdemContainer.SetLayout(hMdemScroll)
|
mdemContainer.SetLayout(hMdemScroll)
|
||||||
|
|
||||||
|
errorBox = widgets.NewQWidget(nil, 0)
|
||||||
|
hErrorBox := widgets.NewQHBoxLayout2(nil)
|
||||||
|
errorBox.SetLayout(hErrorBox)
|
||||||
|
errorLabel = widgets.NewQLabel(nil, 0)
|
||||||
|
errorLabel.SetText("Error")
|
||||||
|
errorBox.Layout().AddWidget(errorLabel)
|
||||||
|
hErrorBox.AddStretch(1)
|
||||||
|
hMdemScroll.AddWidget(errorBox, 0, 0)
|
||||||
|
errorBox.SetObjectName("error")
|
||||||
|
errorBox.SetStyleSheet(`
|
||||||
|
QWidget#error {
|
||||||
|
border: 1px solid #dc143c;
|
||||||
|
background-color: white;
|
||||||
|
padding: 10px 0px;
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
errorBox.Hide()
|
||||||
|
|
||||||
for i := 0; i < 40; i++ {
|
for i := 0; i < 40; i++ {
|
||||||
mdem := CreateMdem()
|
mdem := CreateMdem()
|
||||||
mdems = append(
|
mdems = append(
|
||||||
@@ -428,6 +453,13 @@ func main() {
|
|||||||
)
|
)
|
||||||
hMdemScroll.AddWidget(mdem.wMdem, 0, 0)
|
hMdemScroll.AddWidget(mdem.wMdem, 0, 0)
|
||||||
}
|
}
|
||||||
|
mdemSpacer = widgets.NewQSpacerItem(
|
||||||
|
40,
|
||||||
|
40,
|
||||||
|
widgets.QSizePolicy__Minimum,
|
||||||
|
widgets.QSizePolicy__Expanding,
|
||||||
|
)
|
||||||
|
hMdemScroll.AddItem(mdemSpacer)
|
||||||
|
|
||||||
// CreateMdems
|
// CreateMdems
|
||||||
rightLayout.AddWidget(mdemScroll, 1, 0)
|
rightLayout.AddWidget(mdemScroll, 1, 0)
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user