mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
vlib: add toml module + tests (#11964)
This commit is contained in:
28
vlib/toml/ast/ast.v
Normal file
28
vlib/toml/ast/ast.v
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2021 Lars Pontoppidan. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
module ast
|
||||
|
||||
import toml.input
|
||||
|
||||
// Root represents the root structure of any parsed TOML text snippet or file.
|
||||
[heap]
|
||||
pub struct Root {
|
||||
pub:
|
||||
input input.Config // User input configuration
|
||||
pub mut:
|
||||
table Node
|
||||
// errors []errors.Error // all the checker errors in the file
|
||||
}
|
||||
|
||||
pub fn (r Root) str() string {
|
||||
mut s := typeof(r).name + '{\n'
|
||||
s += ' input: $r.input\n'
|
||||
s += ' table: $r.table\n'
|
||||
s += '}'
|
||||
return s
|
||||
}
|
||||
|
||||
pub fn (r Root) to_json() string {
|
||||
return r.table.to_json()
|
||||
}
|
||||
241
vlib/toml/ast/types.v
Normal file
241
vlib/toml/ast/types.v
Normal file
@@ -0,0 +1,241 @@
|
||||
// Copyright (c) 2021 Lars Pontoppidan. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
module ast
|
||||
|
||||
import toml.token
|
||||
|
||||
// Key is a sumtype representing all types of keys that
|
||||
// can be found in a TOML document.
|
||||
pub type Key = Bare | Bool | Null | Number | Quoted
|
||||
|
||||
pub fn (k Key) str() string {
|
||||
return k.text
|
||||
}
|
||||
|
||||
// Node is a sumtype representing all possible value types
|
||||
// found in a TOML document.
|
||||
pub type Node = Bool | Date | DateTime | Null | Number | Quoted | Time | []Node | map[string]Node
|
||||
|
||||
pub fn (v Node) to_json() string {
|
||||
match v {
|
||||
Quoted, Date, DateTime, Time {
|
||||
return '"$v.text"'
|
||||
}
|
||||
Bool, Null, Number {
|
||||
return v.text
|
||||
}
|
||||
map[string]Node {
|
||||
mut str := '{'
|
||||
for key, val in v {
|
||||
str += ' "$key": $val.to_json(),'
|
||||
}
|
||||
str = str.trim_right(',')
|
||||
str += ' }'
|
||||
return str
|
||||
}
|
||||
[]Node {
|
||||
mut str := '['
|
||||
for val in v {
|
||||
str += ' $val.to_json(),'
|
||||
}
|
||||
str = str.trim_right(',')
|
||||
str += ' ]'
|
||||
return str
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DateTimeType is a sumtype representing all possible date types
|
||||
// found in a TOML document.
|
||||
pub type DateTimeType = Date | DateTime | Time
|
||||
|
||||
pub fn (dtt DateTimeType) str() string {
|
||||
return dtt.text
|
||||
}
|
||||
|
||||
// value queries a value from the map.
|
||||
// `key` should be in "dotted" form e.g.: `"a.b.c.d"`
|
||||
pub fn (v map[string]Node) value(key string) &Node {
|
||||
null := &Node(Null{})
|
||||
key_split := key.split('.')
|
||||
// util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, ' retreiving value at "$key"')
|
||||
if key_split[0] in v.keys() {
|
||||
value := v[key_split[0]] or {
|
||||
return null
|
||||
// TODO return error(@MOD + '.' + @STRUCT + '.' + @FN + ' key "$key" does not exist')
|
||||
}
|
||||
// `match` isn't currently very suitable for these types of sum type constructs...
|
||||
if value is map[string]Node {
|
||||
m := (value as map[string]Node)
|
||||
next_key := key_split[1..].join('.')
|
||||
if next_key == '' {
|
||||
return &value
|
||||
}
|
||||
return m.value(next_key)
|
||||
}
|
||||
return &value
|
||||
}
|
||||
return null
|
||||
// TODO return error(@MOD + '.' + @STRUCT + '.' + @FN + ' key "$key" does not exist')
|
||||
}
|
||||
|
||||
// value queries a value from the map.
|
||||
pub fn (v map[string]Node) exists(key string) bool {
|
||||
key_split := key.split('.')
|
||||
if key_split[0] in v.keys() {
|
||||
value := v[key_split[0]] or { return false }
|
||||
// `match` isn't currently very suitable for these types of sum type constructs...
|
||||
if value is map[string]Node {
|
||||
m := (value as map[string]Node)
|
||||
next_key := key_split[1..].join('.')
|
||||
if next_key == '' {
|
||||
return true
|
||||
}
|
||||
return m.exists(next_key)
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
pub struct Comment {
|
||||
pub:
|
||||
text string
|
||||
pos token.Position
|
||||
}
|
||||
|
||||
pub fn (c Comment) str() string {
|
||||
mut s := typeof(c).name + '{\n'
|
||||
s += ' text: \'$c.text\'\n'
|
||||
s += ' pos: $c.pos\n'
|
||||
s += '}'
|
||||
return s
|
||||
}
|
||||
|
||||
// Null is used in sumtype checks as a "default" value when nothing else is possible.
|
||||
pub struct Null {
|
||||
pub:
|
||||
text string
|
||||
pos token.Position
|
||||
}
|
||||
|
||||
pub fn (n Null) str() string {
|
||||
return n.text
|
||||
}
|
||||
|
||||
pub struct Quoted {
|
||||
pub:
|
||||
text string
|
||||
pos token.Position
|
||||
}
|
||||
|
||||
pub fn (q Quoted) str() string {
|
||||
mut str := typeof(q).name + '{\n'
|
||||
str += ' text: \'$q.text\'\n'
|
||||
str += ' pos: $q.pos\n'
|
||||
str += '}'
|
||||
return str
|
||||
}
|
||||
|
||||
pub struct Bare {
|
||||
pub:
|
||||
text string
|
||||
pos token.Position
|
||||
}
|
||||
|
||||
pub fn (b Bare) str() string {
|
||||
mut str := typeof(b).name + '{\n'
|
||||
str += ' text: \'$b.text\'\n'
|
||||
str += ' pos: $b.pos\n'
|
||||
str += '}'
|
||||
return str
|
||||
}
|
||||
|
||||
pub struct Bool {
|
||||
pub:
|
||||
text string
|
||||
pos token.Position
|
||||
}
|
||||
|
||||
pub fn (b Bool) str() string {
|
||||
mut str := typeof(b).name + '{\n'
|
||||
str += ' text: \'$b.text\'\n'
|
||||
str += ' pos: $b.pos\n'
|
||||
str += '}'
|
||||
return str
|
||||
}
|
||||
|
||||
pub struct Number {
|
||||
pub:
|
||||
text string
|
||||
pos token.Position
|
||||
}
|
||||
|
||||
pub fn (n Number) str() string {
|
||||
mut str := typeof(n).name + '{\n'
|
||||
str += ' text: \'$n.text\'\n'
|
||||
str += ' pos: $n.pos\n'
|
||||
str += '}'
|
||||
return str
|
||||
}
|
||||
|
||||
pub struct Date {
|
||||
pub:
|
||||
text string
|
||||
pos token.Position
|
||||
}
|
||||
|
||||
pub fn (d Date) str() string {
|
||||
mut str := typeof(d).name + '{\n'
|
||||
str += ' text: \'$d.text\'\n'
|
||||
str += ' pos: $d.pos\n'
|
||||
str += '}'
|
||||
return str
|
||||
}
|
||||
|
||||
pub struct Time {
|
||||
pub:
|
||||
text string
|
||||
offset int
|
||||
pos token.Position
|
||||
}
|
||||
|
||||
pub fn (t Time) str() string {
|
||||
mut str := typeof(t).name + '{\n'
|
||||
str += ' text: \'$t.text\'\n'
|
||||
str += ' offset: \'$t.offset\'\n'
|
||||
str += ' pos: $t.pos\n'
|
||||
str += '}'
|
||||
return str
|
||||
}
|
||||
|
||||
pub struct DateTime {
|
||||
pub:
|
||||
text string
|
||||
pos token.Position
|
||||
date Date
|
||||
time Time
|
||||
}
|
||||
|
||||
pub fn (dt DateTime) str() string {
|
||||
mut str := typeof(dt).name + '{\n'
|
||||
str += ' text: \'$dt.text\'\n'
|
||||
str += ' date: \'$dt.date\'\n'
|
||||
str += ' time: \'$dt.time\'\n'
|
||||
str += ' pos: $dt.pos\n'
|
||||
str += '}'
|
||||
return str
|
||||
}
|
||||
|
||||
pub struct EOF {
|
||||
pub:
|
||||
pos token.Position
|
||||
}
|
||||
|
||||
pub fn (e EOF) str() string {
|
||||
mut str := typeof(e).name + '{\n'
|
||||
str += ' pos: $e.pos\n'
|
||||
str += '}'
|
||||
return str
|
||||
}
|
||||
37
vlib/toml/ast/walker/walker.v
Normal file
37
vlib/toml/ast/walker/walker.v
Normal file
@@ -0,0 +1,37 @@
|
||||
module walker
|
||||
|
||||
import toml.ast
|
||||
|
||||
// Visitor defines a visit method which is invoked by the walker in each node it encounters.
|
||||
pub interface Visitor {
|
||||
visit(node &ast.Node) ?
|
||||
}
|
||||
|
||||
pub type InspectorFn = fn (node &ast.Node, data voidptr) ?
|
||||
|
||||
struct Inspector {
|
||||
inspector_callback InspectorFn
|
||||
mut:
|
||||
data voidptr
|
||||
}
|
||||
|
||||
pub fn (i &Inspector) visit(node &ast.Node) ? {
|
||||
i.inspector_callback(node, i.data) or { return err }
|
||||
}
|
||||
|
||||
// inspect traverses and checks the AST node on a depth-first order and based on the data given
|
||||
pub fn inspect(node &ast.Node, data voidptr, inspector_callback InspectorFn) ? {
|
||||
walk(Inspector{inspector_callback, data}, node) ?
|
||||
}
|
||||
|
||||
// walk traverses the AST using the given visitor
|
||||
pub fn walk(visitor Visitor, node &ast.Node) ? {
|
||||
if node is map[string]ast.Node {
|
||||
n := node as map[string]ast.Node
|
||||
for _, nn in n {
|
||||
walk(visitor, &nn) ?
|
||||
}
|
||||
} else {
|
||||
visitor.visit(node) ?
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user