Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions challenge-02/cmd/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package main

import (
"fmt"
"io"
"os"

"github.com/priyanshsao/coding-challenges-go/challenge-02/json"
"github.com/sirupsen/logrus"
)

func main() {

setLogger()

path := "./tests/step2/invalid2.json"
file, err := os.Open(path)
if err != nil {
logrus.Error(err)
return
}
defer file.Close()

fileData, _ := io.ReadAll(file)

parser := json.NewParser(fileData)

res, err := parser.Parse()
if err != nil {
logrus.Errorf("unable to parse: %v", err)
return
}

fmt.Println(res)
}

func setLogger() {

// remove unwanted things and enforce colors
logrus.SetFormatter(&logrus.TextFormatter{
ForceColors: true,
DisableLevelTruncation: true,
})

// set log level to debug.
logrus.SetLevel(logrus.DebugLevel)
}
100 changes: 50 additions & 50 deletions challenge-02/diagrams/lexer.mmd
Original file line number Diff line number Diff line change
@@ -1,51 +1,51 @@
flowchart TD

%% base structure
root["NextToken()"] --> sws["SkipWhiteSpace()"] --> case{case}

%% Characters
bo["{"]
eo["}"]
ba["["]
ea["]"]
ns[":"]
vs[","]
str["string"]
eof["EOF (0)"]
df["default"]
dgom["digit or -"]
lit["literal"]

%% Functions
rn["ReadNum()"]
rl["ReadLiteral()"]
rs["ReadString()"]

%% Return values
t_bo["BeginObject Token"]
t_eo["EndObject Token"]
t_ba["BeginArray Token"]
t_ea["EndArray Token"]
t_ns["NameSeparator Token"]
t_vs["ValueSeparator Token"]
t_str["String Token"]
t_num["Number Token"]
t_lit["True/False/Null Token"]
t_eof["EOF"]
t_illegal["Illegal Token"]

%% Flow
case --> bo --> t_bo
case --> eo --> t_eo
case --> ba --> t_ba
case --> ea --> t_ea
case --> str --> rs --> t_str
case --> ns --> t_ns
case --> vs --> t_vs
case --> eof --> t_eof

case --> df --> cond{if}

cond --> dgom --> rn --> t_num
cond --> lit --> rl --> t_lit
flowchart TD
%% base structure
root["NextToken()"] --> sws["skipWhiteSpace()"] --> case{case}
%% Characters
bo["{"]
eo["}"]
ba["["]
ea["]"]
ns[":"]
vs[","]
str["string"]
eof["EOF (0)"]
df["default"]
dgom["digit or -"]
lit["literal"]
%% Functions
rn["readNum()"]
rl["readLiteral()"]
rs["readString()"]
%% Return values
t_bo["BeginObject Token"]
t_eo["EndObject Token"]
t_ba["BeginArray Token"]
t_ea["EndArray Token"]
t_ns["NameSeparator Token"]
t_vs["ValueSeparator Token"]
t_str["String Token"]
t_num["Number Token"]
t_lit["True/False/Null Token"]
t_eof["EOF"]
t_illegal["Illegal Token"]
%% Flow
case --> bo --> t_bo
case --> eo --> t_eo
case --> ba --> t_ba
case --> ea --> t_ea
case --> str --> rs --> t_str
case --> ns --> t_ns
case --> vs --> t_vs
case --> eof --> t_eof
case --> df --> cond{if}
cond --> dgom --> rn --> t_num
cond --> lit --> rl --> t_lit
cond -->|"else"| t_illegal
46 changes: 23 additions & 23 deletions challenge-02/diagrams/parser.mmd
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
flowchart TD

%% Base Structure
root["Parse()"] --> pt["ParseToken()"] --> |"Move()"| cond{if} --> |equals to EOF| R1[Return parsed object]

%% Functions
f_po["ParseObject()"]
f_pa["ParseArray()"]

pt --> case{"case(current token)"}

case --> |LITERAL| R2["return true/false/nil"]
case --> |NUMBER| R3["return float(token.literal)"]
case --> |STRING| R4["return token.literal"]
case --> |BEGIN_OBJECT| f_po
case --> |BEGIN_ARRAY| f_pa
case --> |EOF| R5["return error"]
case --> |ILLEGAL| R8["return error"]
case --> |DEFAULT| R9["return error"]

f_po --> |"find value of token"| pt
f_po --> |"found EOF"| R6["return object"]
f_pa --> |"find value of token"| pt
flowchart TD
%% Base Structure
root["Parse()"] --> pt["parseToken()"] --> |"move()"| cond{if} --> |equals to EOF| R1[Return parsed object]
%% Functions
f_po["parseObject()"]
f_pa["parseArray()"]
pt --> case{"case(current token)"}
case --> |LITERAL| R2["return true/false/nil"]
case --> |NUMBER| R3["return float(token.literal)"]
case --> |STRING| R4["return token.literal"]
case --> |BEGIN_OBJECT| f_po
case --> |BEGIN_ARRAY| f_pa
case --> |EOF| R5["return error"]
case --> |ILLEGAL| R8["return error"]
case --> |DEFAULT| R9["return error"]
f_po --> |"find value of token"| pt
f_po --> |"found EOF"| R6["return object"]
f_pa --> |"find value of token"| pt
f_pa --> |"found EOF"| R7["return array"]
78 changes: 78 additions & 0 deletions challenge-02/internal/define/tokens.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package define

// TokenType denotes tokens, can be one of this :
// structural, value, special.
type TokenType string

// Structural tokens
const (
// BeginArray denotes starting of array.
BeginArray TokenType = "["
// BeginObject denotes starting of json-object.
BeginObject TokenType = "{"
// EndArray denotes end of an array.
EndArray TokenType = "]"
// EndObject denotes end of json-object.
EndObject TokenType = "}"
// NameSeperator denotes separation between
// json key-value pairs.
NameSeparator TokenType = ":"
// ValueSeperator denotes separation between
// elements in json-object.
ValueSeparator TokenType = ","
)

// Value tokens
const (
// String denotes a normal string value.
String TokenType = "string"
// Number denotes numbers : int, float etc.
Number TokenType = "number"
// True denotes true literal.
True TokenType = "true"
// False denotes false literal.
False TokenType = "false"
// Null denotes null value (acc to json-spec).
Null TokenType = "null"
)

// Special
const (
// EOF denotes the end of file.
EOF TokenType = "EOF"
// Illegal denotes unkown charcters,
// that are not defined in language grammer.
Illegal TokenType = "ILLEGAL"
)

// Token represents a token with it's type and value.
type Token struct {
Type TokenType
Literal string
}

func (tt TokenType) String() string {

switch tt {
case BeginObject:
return "BeginObject"
case EndObject:
return "EndObject"
case BeginArray:
return "BeginArray"
case EndArray:
return "EndArray"
case NameSeparator:
return "NameSeperator"
case ValueSeparator:
return "ValueSeperator"
case Number:
return "Number"
default:
if tt == True || tt == False || tt == Null {
return "Literal"
}

return "Unknown"
}
}
17 changes: 17 additions & 0 deletions challenge-02/internal/lexer/define.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package lexer

// Lexer converts input characters into predefined language tokens.
// It stores data such as the actual input, current character, current position
// of lexer etc.
type Lexer struct {
// input stores the input to be processed.
input []byte
// char stores the current character that needs to be processed.
char byte
// position stores the position of character we are at.
position int
// next stores the postion of character next to the current character.
next int
// line stores the line number of current character.
line int
}
Loading
Loading