From 6432feba9cd615b2de114102bc7403e4486012b1 Mon Sep 17 00:00:00 2001 From: zhuliquan Date: Thu, 29 Jun 2023 22:58:36 +0800 Subject: [PATCH 01/11] feature: support raw string with char ` --- parser/lexer/lexer.go | 13 +++++++++++++ parser/lexer/state.go | 9 +++++++++ parser/parser_test.go | 27 +++++++++++++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/parser/lexer/lexer.go b/parser/lexer/lexer.go index cfb1e8c61..8cda245c8 100644 --- a/parser/lexer/lexer.go +++ b/parser/lexer/lexer.go @@ -219,3 +219,16 @@ func (l *lexer) scanString(quote rune) (n int) { } return } + +func (l *lexer) scanRawString(quote rune) (n int) { + ch := l.next() // read character after quote + for ch != quote { + if ch == eof { + l.error("literal not terminated") + return + } + ch = l.next() + n++ + } + return +} diff --git a/parser/lexer/state.go b/parser/lexer/state.go index 1212aa321..19783e834 100644 --- a/parser/lexer/state.go +++ b/parser/lexer/state.go @@ -1,6 +1,7 @@ package lexer import ( + "strconv" "strings" ) @@ -21,6 +22,14 @@ func root(l *lexer) stateFn { l.error("%v", err) } l.emitValue(String, str) + case r == '`': // raw string case + l.scanRawString(r) + n := len(l.word()) + str, err := unescape(strconv.Quote(l.word()[1 : n-1])) + if err != nil { + l.error("%v", err) + } + l.emitValue(String, str) case '0' <= r && r <= '9': l.backup() return number diff --git a/parser/parser_test.go b/parser/parser_test.go index a93ecdc2f..707c4389d 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -444,6 +444,24 @@ func TestParse(t *testing.T) { Left: &IdentifierNode{Value: "foo"}, Right: &CallNode{Callee: &IdentifierNode{Value: "bar"}}}, }, + { + "`" + `foo\n\rbar\\` + "`", + &StringNode{Value: `foo\n\rbar\\`}, + }, + { + "`" + `foo\ +\n` + "`", + &StringNode{Value: "foo\\\n\\n"}, + }, + { + "`foo\\n\\rbar\\\\`", // because quoted by ", must add '\' to '\' + &StringNode{Value: `foo\n\rbar\\`}, + }, + { + "\"" + `foo\nbar\\` + "\"", + &StringNode{Value: `foo +bar\`}, + }, } for _, test := range parseTests { actual, err := parser.Parse(test.input) @@ -538,6 +556,15 @@ func TestParse_error(t *testing.T) { } } +func TestParseRawString_error(t *testing.T) { + _, err := parser.Parse("`foo") + if err == nil { + t.Errorf("expect to get error") + } else { + t.Logf("got err: %+v", err) + } +} + func TestParse_optional_chaining(t *testing.T) { parseTests := []struct { input string From f3eefa2c28ba2ee050cf341fa12ee7a57f2c3fb6 Mon Sep 17 00:00:00 2001 From: zhuliquan Date: Mon, 24 Jul 2023 01:05:27 +0800 Subject: [PATCH 02/11] feature: reuse common --- ast/node.go | 11 ++ bench_test.go | 35 +++- compiler/check_common.go | 368 +++++++++++++++++++++++++++++++++++++++ compiler/compiler.go | 49 +++++- conf/config.go | 2 + expr.go | 7 + vm/opcodes.go | 3 + vm/program.go | 28 ++- vm/vm.go | 33 +++- 9 files changed, 511 insertions(+), 25 deletions(-) create mode 100644 compiler/check_common.go diff --git a/ast/node.go b/ast/node.go index e85f853e9..253682bd1 100644 --- a/ast/node.go +++ b/ast/node.go @@ -10,6 +10,8 @@ import ( // Node represents items of abstract syntax tree. type Node interface { + SubExpr() string + SetSubExpr(string) Location() file.Location SetLocation(file.Location) Type() reflect.Type @@ -24,6 +26,7 @@ func Patch(node *Node, newNode Node) { type base struct { loc file.Location + subExpr string nodeType reflect.Type } @@ -31,6 +34,14 @@ func (n *base) Location() file.Location { return n.loc } +func (n *base) SubExpr() string { + return n.subExpr +} + +func (n *base) SetSubExpr(s string) { + n.subExpr = s +} + func (n *base) SetLocation(loc file.Location) { n.loc = loc } diff --git a/bench_test.go b/bench_test.go index 1f7f14769..334c3f755 100644 --- a/bench_test.go +++ b/bench_test.go @@ -401,19 +401,40 @@ func Benchmark_realWorld_reuseVm(b *testing.B) { func Benchmark_realWorldInsane(b *testing.B) { env := real_world.NewEnv() expression := `(UserAgentDevice == 'DESKTOP') and (Segments[0].Origin in ['HKT','GOJ'] and Segments[0].Destination in ['HKT','GOJ'] or Segments[0].Origin in ['SKG','GOJ'] and Segments[0].Destination in ['SKG','GOJ'] or Segments[0].Origin in ['SSH','SVX'] and Segments[0].Destination in ['SSH','SVX'] or Segments[0].Origin in ['AYT','LED'] and Segments[0].Destination in ['AYT','LED'] or Segments[0].Origin in ['PUJ','KRR'] and Segments[0].Destination in ['PUJ','KRR'] or Segments[0].Origin in ['USM','CEK'] and Segments[0].Destination in ['USM','CEK'] or Segments[0].Origin in ['SHJ','LED'] and Segments[0].Destination in ['SHJ','LED'] or Segments[0].Origin in ['MOW','PRG'] and Segments[0].Destination in ['MOW','PRG'] or Segments[0].Origin in ['BKK','NOZ'] and Segments[0].Destination in ['BKK','NOZ'] or Segments[0].Origin in ['NHA','GOJ'] and Segments[0].Destination in ['NHA','GOJ'] or Segments[0].Origin in ['HRG','VOG'] and Segments[0].Destination in ['HRG','VOG'] or Segments[0].Origin in ['CFU','MSQ'] and Segments[0].Destination in ['CFU','MSQ'] or Segments[0].Origin in ['UFA','PUJ'] and Segments[0].Destination in ['UFA','PUJ'] or Segments[0].Origin in ['OMS','PUJ'] and Segments[0].Destination in ['OMS','PUJ'] or Segments[0].Origin in ['SKG','MSQ'] and Segments[0].Destination in ['SKG','MSQ'] or Segments[0].Origin in ['SSH','VOZ'] and Segments[0].Destination in ['SSH','VOZ'] or Segments[0].Origin in ['SSH','EGO'] and Segments[0].Destination in ['SSH','EGO'] or Segments[0].Origin in ['UUS','NHA'] and Segments[0].Destination in ['UUS','NHA'] or Segments[0].Origin in ['PUJ','MCX'] and Segments[0].Destination in ['PUJ','MCX'] or Segments[0].Origin in ['NHA','VVO'] and Segments[0].Destination in ['NHA','VVO'] or Segments[0].Origin in ['SKD','MOW'] and Segments[0].Destination in ['SKD','MOW'] or Segments[0].Origin in ['REN','NHA'] and Segments[0].Destination in ['REN','NHA'] or Segments[0].Origin in ['ASF','VRA'] and Segments[0].Destination in ['ASF','VRA'] or Segments[0].Origin in ['YKS','VRA'] and Segments[0].Destination in ['YKS','VRA'] or Segments[0].Origin in ['MOW','RIX'] and Segments[0].Destination in ['MOW','RIX'] or Segments[0].Origin in ['HER','IEV'] and Segments[0].Destination in ['HER','IEV'] or Segments[0].Origin in ['HRG','EGO'] and Segments[0].Destination in ['HRG','EGO'] or Segments[0].Origin in ['MOW','ATH'] and Segments[0].Destination in ['MOW','ATH'] or Segments[0].Origin in ['EGO','SSH'] and Segments[0].Destination in ['EGO','SSH'] or Segments[0].Origin in ['CEK','CUN'] and Segments[0].Destination in ['CEK','CUN'] or Segments[0].Origin in ['VAR','MOW'] and Segments[0].Destination in ['VAR','MOW'] or Segments[0].Origin in ['ASF','NHA'] and Segments[0].Destination in ['ASF','NHA'] or Segments[0].Origin in ['SKG','OVB'] and Segments[0].Destination in ['SKG','OVB'] or Segments[0].Origin in ['CUN','VOZ'] and Segments[0].Destination in ['CUN','VOZ'] or Segments[0].Origin in ['HRG','OVB'] and Segments[0].Destination in ['HRG','OVB'] or Segments[0].Origin in ['LED','VAR'] and Segments[0].Destination in ['LED','VAR'] or Segments[0].Origin in ['OMS','CUN'] and Segments[0].Destination in ['OMS','CUN'] or Segments[0].Origin in ['PUJ','NOZ'] and Segments[0].Destination in ['PUJ','NOZ'] or Segments[0].Origin in ['CUN','OMS'] and Segments[0].Destination in ['CUN','OMS'] or Segments[0].Origin in ['BAX','NHA'] and Segments[0].Destination in ['BAX','NHA'] or Segments[0].Origin in ['TDX','TJM'] and Segments[0].Destination in ['TDX','TJM'] or Segments[0].Origin in ['BKK','YKS'] and Segments[0].Destination in ['BKK','YKS'] or Segments[0].Origin in ['PUJ','MRV'] and Segments[0].Destination in ['PUJ','MRV'] or Segments[0].Origin in ['KUF','MOW'] and Segments[0].Destination in ['KUF','MOW'] or Segments[0].Origin in ['NHA','YKS'] and Segments[0].Destination in ['NHA','YKS'] or Segments[0].Origin in ['UFA','CUN'] and Segments[0].Destination in ['UFA','CUN'] or Segments[0].Origin in ['MIR','MOW'] and Segments[0].Destination in ['MIR','MOW'] or Segments[0].Origin in ['OVB','PUJ'] and Segments[0].Destination in ['OVB','PUJ'] or Segments[0].Origin in ['SGN','KJA'] and Segments[0].Destination in ['SGN','KJA'] or Segments[0].Origin in ['UTP','CEK'] and Segments[0].Destination in ['UTP','CEK'] or Segments[0].Origin in ['SKG','IEV'] and Segments[0].Destination in ['SKG','IEV'] or Segments[0].Origin in ['PKC','MOW'] and Segments[0].Destination in ['PKC','MOW'] or Segments[0].Origin in ['NHA','OGZ'] and Segments[0].Destination in ['NHA','OGZ'] or Segments[0].Origin in ['USM','UFA'] and Segments[0].Destination in ['USM','UFA'] or Segments[0].Origin in ['KGD','VRA'] and Segments[0].Destination in ['KGD','VRA'] or Segments[0].Origin in ['TDX','KZN'] and Segments[0].Destination in ['TDX','KZN'] or Segments[0].Origin in ['KRR','CUN'] and Segments[0].Destination in ['KRR','CUN'] or Segments[0].Origin in ['DXB','PEE'] and Segments[0].Destination in ['DXB','PEE'] or Segments[0].Origin in ['AER','KUF'] and Segments[0].Destination in ['AER','KUF'] or Segments[0].Origin in ['REN','SSH'] and Segments[0].Destination in ['REN','SSH'] or Segments[0].Origin in ['HKT','NJC'] and Segments[0].Destination in ['HKT','NJC'] or Segments[0].Origin in ['AER','CUN'] and Segments[0].Destination in ['AER','CUN'] or Segments[0].Origin in ['ETH','SVX'] and Segments[0].Destination in ['ETH','SVX'] or Segments[0].Origin in ['SSH','CEK'] and Segments[0].Destination in ['SSH','CEK'] or Segments[0].Origin in ['BKK','UFA'] and Segments[0].Destination in ['BKK','UFA'] or Segments[0].Origin in ['SVX','SKG'] and Segments[0].Destination in ['SVX','SKG'] or Segments[0].Origin in ['BKK','VOG'] and Segments[0].Destination in ['BKK','VOG'] or Segments[0].Origin in ['SKG','MOW'] and Segments[0].Destination in ['SKG','MOW'] or Segments[0].Origin in ['NHA','NOZ'] and Segments[0].Destination in ['NHA','NOZ'] or Segments[0].Origin in ['YKS','OVB'] and Segments[0].Destination in ['YKS','OVB'] or Segments[0].Origin in ['UFA','VRA'] and Segments[0].Destination in ['UFA','VRA'] or Segments[0].Origin in ['MOW','TCI'] and Segments[0].Destination in ['MOW','TCI'] or Segments[0].Origin in ['ASF','PUJ'] and Segments[0].Destination in ['ASF','PUJ'] or Segments[0].Origin in ['GOJ','CUN'] and Segments[0].Destination in ['GOJ','CUN'] or Segments[0].Origin in ['ASF','CUN'] and Segments[0].Destination in ['ASF','CUN'] or Segments[0].Origin in ['SGN','CEK'] and Segments[0].Destination in ['SGN','CEK'] or Segments[0].Origin in ['TJM','SSH'] and Segments[0].Destination in ['TJM','SSH'] or Segments[0].Origin in ['UTP','KZN'] and Segments[0].Destination in ['UTP','KZN'] or Segments[0].Origin in ['HRG','REN'] and Segments[0].Destination in ['HRG','REN'] or Segments[0].Origin in ['HKT','KJA'] and Segments[0].Destination in ['HKT','KJA'] or Segments[0].Origin in ['BEG','MOW'] and Segments[0].Destination in ['BEG','MOW'] or Segments[0].Origin in ['OMS','SSH'] and Segments[0].Destination in ['OMS','SSH'] or Segments[0].Origin in ['MSQ','SKG'] and Segments[0].Destination in ['MSQ','SKG'] or Segments[0].Origin in ['BKK','HTA'] and Segments[0].Destination in ['BKK','HTA'] or Segments[0].Origin in ['TDX','PEE'] and Segments[0].Destination in ['TDX','PEE'] or Segments[0].Origin in ['SKG','MRV'] and Segments[0].Destination in ['SKG','MRV'] or Segments[0].Origin in ['SGN','OVB'] and Segments[0].Destination in ['SGN','OVB'] or Segments[0].Origin in ['SVX','HRG'] and Segments[0].Destination in ['SVX','HRG'] or Segments[0].Origin in ['HKT','AER'] and Segments[0].Destination in ['HKT','AER'] or Segments[0].Origin in ['CEE','CUN'] and Segments[0].Destination in ['CEE','CUN'] or Segments[0].Origin in ['NHA','SVX'] and Segments[0].Destination in ['NHA','SVX'] or Segments[0].Origin in ['CUN','GOJ'] and Segments[0].Destination in ['CUN','GOJ'] or Segments[0].Origin in ['MOW','OGZ'] and Segments[0].Destination in ['MOW','OGZ'] or Segments[0].Origin in ['SCW','SSH'] and Segments[0].Destination in ['SCW','SSH'] or Segments[0].Origin in ['PUJ','PEE'] and Segments[0].Destination in ['PUJ','PEE'] or Segments[0].Origin in ['CUN','ASF'] and Segments[0].Destination in ['CUN','ASF'] or Segments[0].Origin in ['AQJ','SVX'] and Segments[0].Destination in ['AQJ','SVX'] or Segments[0].Origin in ['VRA','IKT'] and Segments[0].Destination in ['VRA','IKT'] or Segments[0].Origin in ['SHJ','SVX'] and Segments[0].Destination in ['SHJ','SVX'] or Segments[0].Origin in ['NBC','VRA'] and Segments[0].Destination in ['NBC','VRA'] or Segments[0].Origin in ['HTA','CUN'] and Segments[0].Destination in ['HTA','CUN'] or Segments[0].Origin in ['MOW','TOF'] and Segments[0].Destination in ['MOW','TOF'] or Segments[0].Origin in ['NJC','CUN'] and Segments[0].Destination in ['NJC','CUN'] or Segments[0].Origin in ['CUN','NOZ'] and Segments[0].Destination in ['CUN','NOZ'] or Segments[0].Origin in ['BTK','NHA'] and Segments[0].Destination in ['BTK','NHA'] or Segments[0].Origin in ['PUJ','OMS'] and Segments[0].Destination in ['PUJ','OMS'] or Segments[0].Origin in ['HTA','OVB'] and Segments[0].Destination in ['HTA','OVB'] or Segments[0].Origin in ['AQJ','KZN'] and Segments[0].Destination in ['AQJ','KZN'] or Segments[0].Origin in ['DXB','VOZ'] and Segments[0].Destination in ['DXB','VOZ'] or Segments[0].Origin in ['NHA','PEE'] and Segments[0].Destination in ['NHA','PEE'] or Segments[0].Origin in ['HKT','OGZ'] and Segments[0].Destination in ['HKT','OGZ'] or Segments[0].Origin in ['KLV','MOW'] and Segments[0].Destination in ['KLV','MOW'] or Segments[0].Origin in ['MRV','SKG'] and Segments[0].Destination in ['MRV','SKG'] or Segments[0].Origin in ['SKG','LED'] and Segments[0].Destination in ['SKG','LED'] or Segments[0].Origin in ['AQJ','MOW'] and Segments[0].Destination in ['AQJ','MOW'] or Segments[0].Origin in ['MOW','NHA'] and Segments[0].Destination in ['MOW','NHA'] or Segments[0].Origin in ['ARH','HRG'] and Segments[0].Destination in ['ARH','HRG'] or Segments[0].Origin in ['SGN','AER'] and Segments[0].Destination in ['SGN','AER'] or Segments[0].Origin in ['VRA','MCX'] and Segments[0].Destination in ['VRA','MCX'] or Segments[0].Origin in ['BKK','OVB'] and Segments[0].Destination in ['BKK','OVB'] or Segments[0].Origin in ['AYT','UFA'] and Segments[0].Destination in ['AYT','UFA'] or Segments[0].Origin in ['SGN','NOZ'] and Segments[0].Destination in ['SGN','NOZ'] or Segments[0].Origin in ['SGN','NBC'] and Segments[0].Destination in ['SGN','NBC'] or Segments[0].Origin in ['MOW','BEG'] and Segments[0].Destination in ['MOW','BEG'] or Segments[0].Origin in ['TDX','BQS'] and Segments[0].Destination in ['TDX','BQS'] or Segments[0].Origin in ['KRR','NHA'] and Segments[0].Destination in ['KRR','NHA'] or Segments[0].Origin in ['NHA','SGC'] and Segments[0].Destination in ['NHA','SGC'] or Segments[0].Origin in ['NHA','UFA'] and Segments[0].Destination in ['NHA','UFA'] or Segments[0].Origin in ['NHA','ARH'] and Segments[0].Destination in ['NHA','ARH'] or Segments[0].Origin in ['EGO','VRA'] and Segments[0].Destination in ['EGO','VRA'] or Segments[0].Origin in ['BCN','MOW'] and Segments[0].Destination in ['BCN','MOW'] or Segments[0].Origin in ['TDX','ROV'] and Segments[0].Destination in ['TDX','ROV'] or Segments[0].Origin in ['TSN','MOW'] and Segments[0].Destination in ['TSN','MOW'] or Segments[0].Origin in ['GOJ','HRG'] and Segments[0].Destination in ['GOJ','HRG'] or Segments[0].Origin in ['BKK','KZN'] and Segments[0].Destination in ['BKK','KZN'] or Segments[0].Origin in ['NHA','ROV'] and Segments[0].Destination in ['NHA','ROV'] or Segments[0].Origin in ['DXB','KJA'] and Segments[0].Destination in ['DXB','KJA'] or Segments[0].Origin in ['PEE','AER'] and Segments[0].Destination in ['PEE','AER'] or Segments[0].Origin in ['DXB','CEK'] and Segments[0].Destination in ['DXB','CEK'] or Segments[0].Origin in ['PUJ','ASF'] and Segments[0].Destination in ['PUJ','ASF'] or Segments[0].Origin in ['KBV','OVB'] and Segments[0].Destination in ['KBV','OVB'] or Segments[0].Origin in ['MOW','EVN'] and Segments[0].Destination in ['MOW','EVN'] or Segments[0].Origin in ['IKT','CUN'] and Segments[0].Destination in ['IKT','CUN'] or Segments[0].Origin in ['KGD','HRG'] and Segments[0].Destination in ['KGD','HRG'] or Segments[0].Origin in ['KBV','PEE'] and Segments[0].Destination in ['KBV','PEE'] or Segments[0].Origin in ['VOG','VRA'] and Segments[0].Destination in ['VOG','VRA'] or Segments[0].Origin in ['MOW','HKT'] and Segments[0].Destination in ['MOW','HKT'] or Segments[0].Origin in ['NHA','ASF'] and Segments[0].Destination in ['NHA','ASF'] or Segments[0].Origin in ['LED','SVX'] and Segments[0].Destination in ['LED','SVX'] or Segments[0].Origin in ['AAQ','CUN'] and Segments[0].Destination in ['AAQ','CUN'] or Segments[0].Origin in ['BKK','KEJ'] and Segments[0].Destination in ['BKK','KEJ'] or Segments[0].Origin in ['BKK','BQS'] and Segments[0].Destination in ['BKK','BQS'] or Segments[0].Origin in ['DXB','IKT'] and Segments[0].Destination in ['DXB','IKT'] or Segments[0].Origin in ['SSH','TJM'] and Segments[0].Destination in ['SSH','TJM'] or Segments[0].Origin in ['PUJ','ROV'] and Segments[0].Destination in ['PUJ','ROV'] or Segments[0].Origin in ['AER','SVX'] and Segments[0].Destination in ['AER','SVX'] or Segments[0].Origin in ['UFA','ETH'] and Segments[0].Destination in ['UFA','ETH'] or Segments[0].Origin in ['BKK','KUF'] and Segments[0].Destination in ['BKK','KUF'] or Segments[0].Origin in ['BKK','VVO'] and Segments[0].Destination in ['BKK','VVO'] or Segments[0].Origin in ['HKT','OVB'] and Segments[0].Destination in ['HKT','OVB'] or Segments[0].Origin in ['ZTH','LED'] and Segments[0].Destination in ['ZTH','LED'] or Segments[0].Origin in ['KZN','NHA'] and Segments[0].Destination in ['KZN','NHA'] or Segments[0].Origin in ['VRA','BAX'] and Segments[0].Destination in ['VRA','BAX'] or Segments[0].Origin in ['RTW','NHA'] and Segments[0].Destination in ['RTW','NHA'] or Segments[0].Origin in ['SKG','DNK'] and Segments[0].Destination in ['SKG','DNK'] or Segments[0].Origin in ['SGN','VOG'] and Segments[0].Destination in ['SGN','VOG'] or Segments[0].Origin in ['KBV','VVO'] and Segments[0].Destination in ['KBV','VVO'] or Segments[0].Origin in ['IEV','CFU'] and Segments[0].Destination in ['IEV','CFU'] or Segments[0].Origin in ['PUJ','TOF'] and Segments[0].Destination in ['PUJ','TOF'] or Segments[0].Origin in ['HKT','KEJ'] and Segments[0].Destination in ['HKT','KEJ'] or Segments[0].Origin in ['PUJ','NJC'] and Segments[0].Destination in ['PUJ','NJC'] or Segments[0].Origin in ['PEE','CUN'] and Segments[0].Destination in ['PEE','CUN'] or Segments[0].Origin in ['HKT','TJM'] and Segments[0].Destination in ['HKT','TJM'] or Segments[0].Origin in ['ETH','KZN'] and Segments[0].Destination in ['ETH','KZN'] or Segments[0].Origin in ['MCX','CUN'] and Segments[0].Destination in ['MCX','CUN'] or Segments[0].Origin in ['HRG','KUF'] and Segments[0].Destination in ['HRG','KUF'] or Segments[0].Origin in ['VRA','VOG'] and Segments[0].Destination in ['VRA','VOG'] or Segments[0].Origin in ['SVX','CUN'] and Segments[0].Destination in ['SVX','CUN'] or Segments[0].Origin in ['VRA','EGO'] and Segments[0].Destination in ['VRA','EGO'] or Segments[0].Origin in ['ROV','CUN'] and Segments[0].Destination in ['ROV','CUN'] or Segments[0].Origin in ['KJA','VRA'] and Segments[0].Destination in ['KJA','VRA'] or Segments[0].Origin in ['VRA','PEE'] and Segments[0].Destination in ['VRA','PEE'] or Segments[0].Origin in ['MOW','SKD'] and Segments[0].Destination in ['MOW','SKD'] or Segments[0].Origin in ['POP','ROV'] and Segments[0].Destination in ['POP','ROV'] or Segments[0].Origin in ['AYT','KZN'] and Segments[0].Destination in ['AYT','KZN'] or Segments[0].Origin in ['ETH','REN'] and Segments[0].Destination in ['ETH','REN'] or Segments[0].Origin in ['ETH','LED'] and Segments[0].Destination in ['ETH','LED'] or Segments[0].Origin in ['CEK','ETH'] and Segments[0].Destination in ['CEK','ETH'] or Segments[0].Origin in ['NHA','VOZ'] and Segments[0].Destination in ['NHA','VOZ'] or Segments[0].Origin in ['SVX','AER'] and Segments[0].Destination in ['SVX','AER'] or Segments[0].Origin in ['FEG','MOW'] and Segments[0].Destination in ['FEG','MOW'] or Segments[0].Origin in ['VRA','KZN'] and Segments[0].Destination in ['VRA','KZN'] or Segments[0].Origin in ['USM','PEE'] and Segments[0].Destination in ['USM','PEE'] or Segments[0].Origin in ['VVO','MOW'] and Segments[0].Destination in ['VVO','MOW'] or Segments[0].Origin in ['SGN','KEJ'] and Segments[0].Destination in ['SGN','KEJ'] or Segments[0].Origin in ['DXB','AER'] and Segments[0].Destination in ['DXB','AER'] or Segments[0].Origin in ['MOW','VOG'] and Segments[0].Destination in ['MOW','VOG'] or Segments[0].Origin in ['SGN','YKS'] and Segments[0].Destination in ['SGN','YKS'] or Segments[0].Origin in ['VRA','NJC'] and Segments[0].Destination in ['VRA','NJC'] or Segments[0].Origin in ['VOG','PUJ'] and Segments[0].Destination in ['VOG','PUJ'] or Segments[0].Origin in ['HKT','MOW'] and Segments[0].Destination in ['HKT','MOW'] or Segments[0].Origin in ['VOG','SKG'] and Segments[0].Destination in ['VOG','SKG'] or Segments[0].Origin in ['OVB','YKS'] and Segments[0].Destination in ['OVB','YKS'] or Segments[0].Origin in ['SGC','SSH'] and Segments[0].Destination in ['SGC','SSH'] or Segments[0].Origin in ['VOZ','NHA'] and Segments[0].Destination in ['VOZ','NHA'] or Segments[0].Origin in ['CUN','NBC'] and Segments[0].Destination in ['CUN','NBC'] or Segments[0].Origin in ['KZN','SSH'] and Segments[0].Destination in ['KZN','SSH'] or Segments[0].Origin in ['HER','MOW'] and Segments[0].Destination in ['HER','MOW'] or Segments[0].Origin in ['TDX','UFA'] and Segments[0].Destination in ['TDX','UFA'] or Segments[0].Origin in ['KZN','ETH'] and Segments[0].Destination in ['KZN','ETH'] or Segments[0].Origin in ['ABA','CUN'] and Segments[0].Destination in ['ABA','CUN'] or Segments[0].Origin in ['PEE','NHA'] and Segments[0].Destination in ['PEE','NHA'] or Segments[0].Origin in ['CUN','TOF'] and Segments[0].Destination in ['CUN','TOF'] or Segments[0].Origin in ['TJM','HRG'] and Segments[0].Destination in ['TJM','HRG'] or Segments[0].Origin in ['EGO','HRG'] and Segments[0].Destination in ['EGO','HRG'] or Segments[0].Origin in ['GOJ','SSH'] and Segments[0].Destination in ['GOJ','SSH'] or Segments[0].Origin in ['HKT','HTA'] and Segments[0].Destination in ['HKT','HTA'] or Segments[0].Origin in ['MOW','ETH'] and Segments[0].Destination in ['MOW','ETH'] or Segments[0].Origin in ['OGZ','VRA'] and Segments[0].Destination in ['OGZ','VRA'] or Segments[0].Origin in ['HKT','NBC'] and Segments[0].Destination in ['HKT','NBC'] or Segments[0].Origin in ['GPA','MSQ'] and Segments[0].Destination in ['GPA','MSQ'] or Segments[0].Origin in ['SGN','TOF'] and Segments[0].Destination in ['SGN','TOF'] or Segments[0].Origin in ['HKT','MCX'] and Segments[0].Destination in ['HKT','MCX'] or Segments[0].Origin in ['KRR','VRA'] and Segments[0].Destination in ['KRR','VRA'] or Segments[0].Origin in ['ROV','PUJ'] and Segments[0].Destination in ['ROV','PUJ'] or Segments[0].Origin in ['CEE','VRA'] and Segments[0].Destination in ['CEE','VRA'] or Segments[0].Origin in ['TJM','NHA'] and Segments[0].Destination in ['TJM','NHA'] or Segments[0].Origin in ['RTW','CUN'] and Segments[0].Destination in ['RTW','CUN'] or Segments[0].Origin in ['AER','KZN'] and Segments[0].Destination in ['AER','KZN'] or Segments[0].Origin in ['MRV','ETH'] and Segments[0].Destination in ['MRV','ETH'] or Segments[0].Origin in ['SGN','VOZ'] and Segments[0].Destination in ['SGN','VOZ'] or Segments[0].Origin in ['USM','BQS'] and Segments[0].Destination in ['USM','BQS'] or Segments[0].Origin in ['USM','SGC'] and Segments[0].Destination in ['USM','SGC'] or Segments[0].Origin in ['HER','SVX'] and Segments[0].Destination in ['HER','SVX'] or Segments[0].Origin in ['DXB','KZN'] and Segments[0].Destination in ['DXB','KZN'] or Segments[0].Origin in ['TDX','KEJ'] and Segments[0].Destination in ['TDX','KEJ'] or Segments[0].Origin in ['HRG','SGC'] and Segments[0].Destination in ['HRG','SGC'] or Segments[0].Origin in ['SOF','LED'] and Segments[0].Destination in ['SOF','LED'] or Segments[0].Origin in ['DXB','UFA'] and Segments[0].Destination in ['DXB','UFA'] or Segments[0].Origin in ['EVN','MOW'] and Segments[0].Destination in ['EVN','MOW'] or Segments[0].Origin in ['HKT','LED'] and Segments[0].Destination in ['HKT','LED'] or Segments[0].Origin in ['SGN','NJC'] and Segments[0].Destination in ['SGN','NJC'] or Segments[0].Origin in ['SHJ','KUF'] and Segments[0].Destination in ['SHJ','KUF'] or Segments[0].Origin in ['AQJ','LED'] and Segments[0].Destination in ['AQJ','LED'] or Segments[0].Origin in ['HRG','GOJ'] and Segments[0].Destination in ['HRG','GOJ'] or Segments[0].Origin in ['PRG','LED'] and Segments[0].Destination in ['PRG','LED'] or Segments[0].Origin in ['NOZ','NHA'] and Segments[0].Destination in ['NOZ','NHA'] or Segments[0].Origin in ['ARH','SSH'] and Segments[0].Destination in ['ARH','SSH'] or Segments[0].Origin in ['SSH','REN'] and Segments[0].Destination in ['SSH','REN'] or Segments[0].Origin in ['AYT','GOJ'] and Segments[0].Destination in ['AYT','GOJ'] or Segments[0].Origin in ['ATH','MSQ'] and Segments[0].Destination in ['ATH','MSQ'] or Segments[0].Origin in ['MOW','VAR'] and Segments[0].Destination in ['MOW','VAR'] or Segments[0].Origin in ['HER','LED'] and Segments[0].Destination in ['HER','LED'] or Segments[0].Origin in ['SIP','KJA'] and Segments[0].Destination in ['SIP','KJA'] or Segments[0].Origin in ['TJM','CUN'] and Segments[0].Destination in ['TJM','CUN'] or Segments[0].Origin in ['PUJ','LED'] and Segments[0].Destination in ['PUJ','LED'] or Segments[0].Origin in ['BKK','SGC'] and Segments[0].Destination in ['BKK','SGC'] or Segments[0].Origin in ['PUJ','KEJ'] and Segments[0].Destination in ['PUJ','KEJ'] or Segments[0].Origin in ['BKK','KJA'] and Segments[0].Destination in ['BKK','KJA'] or Segments[0].Origin in ['DXB','VOG'] and Segments[0].Destination in ['DXB','VOG'] or Segments[0].Origin in ['PUJ','KJA'] and Segments[0].Destination in ['PUJ','KJA'] or Segments[0].Origin in ['RMI','MOW'] and Segments[0].Destination in ['RMI','MOW'] or Segments[0].Origin in ['USM','KEJ'] and Segments[0].Destination in ['USM','KEJ'] or Segments[0].Origin in ['MOW','RVN'] and Segments[0].Destination in ['MOW','RVN'] or Segments[0].Origin in ['VRA','AER'] and Segments[0].Destination in ['VRA','AER'] or Segments[0].Origin in ['SGN','VVO'] and Segments[0].Destination in ['SGN','VVO'] or Segments[0].Origin in ['SIP','MOW'] and Segments[0].Destination in ['SIP','MOW'] or Segments[0].Origin in ['ETH','MRV'] and Segments[0].Destination in ['ETH','MRV'] or Segments[0].Origin in ['VRA','MRV'] and Segments[0].Destination in ['VRA','MRV'] or Segments[0].Origin in ['ROV','MOW'] and Segments[0].Destination in ['ROV','MOW'] or Segments[0].Origin in ['KBV','TJM'] and Segments[0].Destination in ['KBV','TJM'] or Segments[0].Origin in ['PUJ','VOZ'] and Segments[0].Destination in ['PUJ','VOZ'] or Segments[0].Origin in ['LED','AER'] and Segments[0].Destination in ['LED','AER'] or Segments[0].Origin in ['AER','VRA'] and Segments[0].Destination in ['AER','VRA'] or Segments[0].Origin in ['CUN','SVX'] and Segments[0].Destination in ['CUN','SVX'] or Segments[0].Origin in ['HKT','ROV'] and Segments[0].Destination in ['HKT','ROV'] or Segments[0].Origin in ['KUF','NHA'] and Segments[0].Destination in ['KUF','NHA'] or Segments[0].Origin in ['KGD','SKG'] and Segments[0].Destination in ['KGD','SKG'] or Segments[0].Origin in ['DXB','YKS'] and Segments[0].Destination in ['DXB','YKS'] or Segments[0].Origin in ['AER','PEE'] and Segments[0].Destination in ['AER','PEE'] or Segments[0].Origin in ['ROV','CFU'] and Segments[0].Destination in ['ROV','CFU'] or Segments[0].Origin in ['VOG','CUN'] and Segments[0].Destination in ['VOG','CUN'] or Segments[0].Origin in ['PUJ','KZN'] and Segments[0].Destination in ['PUJ','KZN'] or Segments[0].Origin in ['MOW','SZG'] and Segments[0].Destination in ['MOW','SZG'] or Segments[0].Origin in ['GDX','MOW'] and Segments[0].Destination in ['GDX','MOW'] or Segments[0].Origin in ['HKT','VOG'] and Segments[0].Destination in ['HKT','VOG'] or Segments[0].Origin in ['BOJ','MOW'] and Segments[0].Destination in ['BOJ','MOW'] or Segments[0].Origin in ['OVB','HTA'] and Segments[0].Destination in ['OVB','HTA'] or Segments[0].Origin in ['BKK','EGO'] and Segments[0].Destination in ['BKK','EGO'] or Segments[0].Origin in ['ETH','KUF'] and Segments[0].Destination in ['ETH','KUF'] or Segments[0].Origin in ['HRG','ARH'] and Segments[0].Destination in ['HRG','ARH'] or Segments[0].Origin in ['MOW','KGD'] and Segments[0].Destination in ['MOW','KGD'] or Segments[0].Origin in ['HRG','CEK'] and Segments[0].Destination in ['HRG','CEK'] or Segments[0].Origin in ['LED','HER'] and Segments[0].Destination in ['LED','HER'] or Segments[0].Origin in ['USM','IKT'] and Segments[0].Destination in ['USM','IKT'] or Segments[0].Origin in ['CUN','TJM'] and Segments[0].Destination in ['CUN','TJM'] or Segments[0].Origin in ['NHA','UUS'] and Segments[0].Destination in ['NHA','UUS'] or Segments[0].Origin in ['NHA','KZN'] and Segments[0].Destination in ['NHA','KZN'] or Segments[0].Origin in ['NBC','HRG'] and Segments[0].Destination in ['NBC','HRG'] or Segments[0].Origin in ['SKG','SVX'] and Segments[0].Destination in ['SKG','SVX'] or Segments[0].Origin in ['HRG','UFA'] and Segments[0].Destination in ['HRG','UFA'] or Segments[0].Origin in ['TDX','MOW'] and Segments[0].Destination in ['TDX','MOW'] or Segments[0].Origin in ['LED','SKG'] and Segments[0].Destination in ['LED','SKG'] or Segments[0].Origin in ['SGN','SVX'] and Segments[0].Destination in ['SGN','SVX'] or Segments[0].Origin in ['CUN','AER'] and Segments[0].Destination in ['CUN','AER'] or Segments[0].Origin in ['MOW','KUT'] and Segments[0].Destination in ['MOW','KUT'] or Segments[0].Origin in ['VRN','KRR'] and Segments[0].Destination in ['VRN','KRR'] or Segments[0].Origin in ['MSQ','ATH'] and Segments[0].Destination in ['MSQ','ATH'] or Segments[0].Origin in ['PUJ','BAX'] and Segments[0].Destination in ['PUJ','BAX'] or Segments[0].Origin in ['KEJ','CUN'] and Segments[0].Destination in ['KEJ','CUN'] or Segments[0].Origin in ['KUF','PUJ'] and Segments[0].Destination in ['KUF','PUJ'] or Segments[0].Origin in ['VRA','KUF'] and Segments[0].Destination in ['VRA','KUF'] or Segments[0].Origin in ['LED','HRG'] and Segments[0].Destination in ['LED','HRG'] or Segments[0].Origin in ['BKK','ASF'] and Segments[0].Destination in ['BKK','ASF'] or Segments[0].Origin in ['IEV','HER'] and Segments[0].Destination in ['IEV','HER'] or Segments[0].Origin in ['SHJ','ROV'] and Segments[0].Destination in ['SHJ','ROV'] or Segments[0].Origin in ['KUT','MOW'] and Segments[0].Destination in ['KUT','MOW'] or Segments[0].Origin in ['HKT','KRR'] and Segments[0].Destination in ['HKT','KRR'] or Segments[0].Origin in ['AYT','MOW'] and Segments[0].Destination in ['AYT','MOW'] or Segments[0].Origin in ['VRA','MOW'] and Segments[0].Destination in ['VRA','MOW'] or Segments[0].Origin in ['SCW','PUJ'] and Segments[0].Destination in ['SCW','PUJ'] or Segments[0].Origin in ['MOW','TAS'] and Segments[0].Destination in ['MOW','TAS'] or Segments[0].Origin in ['IEV','SKG'] and Segments[0].Destination in ['IEV','SKG'] or Segments[0].Origin in ['LED','BOJ'] and Segments[0].Destination in ['LED','BOJ'] or Segments[0].Origin in ['HKT','SVX'] and Segments[0].Destination in ['HKT','SVX'] or Segments[0].Origin in ['BKK','SVX'] and Segments[0].Destination in ['BKK','SVX'] or Segments[0].Origin in ['SGN','MOW'] and Segments[0].Destination in ['SGN','MOW'] or Segments[0].Origin in ['SVX','ETH'] and Segments[0].Destination in ['SVX','ETH'] or Segments[0].Origin in ['SSH','PEE'] and Segments[0].Destination in ['SSH','PEE'] or Segments[0].Origin in ['NHA','KUF'] and Segments[0].Destination in ['NHA','KUF'] or Segments[0].Origin in ['SSH','KUF'] and Segments[0].Destination in ['SSH','KUF'] or Segments[0].Origin in ['DXB','MOW'] and Segments[0].Destination in ['DXB','MOW'] or Segments[0].Origin in ['PUJ','YKS'] and Segments[0].Destination in ['PUJ','YKS'] or Segments[0].Origin in ['SSH','ARH'] and Segments[0].Destination in ['SSH','ARH'] or Segments[0].Origin in ['AUH','MOW'] and Segments[0].Destination in ['AUH','MOW'] or Segments[0].Origin in ['UTP','IKT'] and Segments[0].Destination in ['UTP','IKT'] or Segments[0].Origin in ['KRR','SSH'] and Segments[0].Destination in ['KRR','SSH'] or Segments[0].Origin in ['HRG','KZN'] and Segments[0].Destination in ['HRG','KZN'] or Segments[0].Origin in ['BKK','ROV'] and Segments[0].Destination in ['BKK','ROV'] or Segments[0].Origin in ['CEK','PUJ'] and Segments[0].Destination in ['CEK','PUJ'] or Segments[0].Origin in ['SGN','KGD'] and Segments[0].Destination in ['SGN','KGD'] or Segments[0].Origin in ['KEJ','PUJ'] and Segments[0].Destination in ['KEJ','PUJ'] or Segments[0].Origin in ['HKT','SCW'] and Segments[0].Destination in ['HKT','SCW'] or Segments[0].Origin in ['BKK','KGD'] and Segments[0].Destination in ['BKK','KGD'] or Segments[0].Origin in ['HKT','SGC'] and Segments[0].Destination in ['HKT','SGC'] or Segments[0].Origin in ['REN','HRG'] and Segments[0].Destination in ['REN','HRG'] or Segments[0].Origin in ['SKG','TSE'] and Segments[0].Destination in ['SKG','TSE'] or Segments[0].Origin in ['BKK','PKC'] and Segments[0].Destination in ['BKK','PKC'] or Segments[0].Origin in ['VRA','KJA'] and Segments[0].Destination in ['VRA','KJA'] or Segments[0].Origin in ['SCW','CUN'] and Segments[0].Destination in ['SCW','CUN'] or Segments[0].Origin in ['SKG','KZN'] and Segments[0].Destination in ['SKG','KZN'] or Segments[0].Origin in ['MOW','GRV'] and Segments[0].Destination in ['MOW','GRV'] or Segments[0].Origin in ['HRG','NBC'] and Segments[0].Destination in ['HRG','NBC'] or Segments[0].Origin in ['SCW','VRA'] and Segments[0].Destination in ['SCW','VRA'] or Segments[0].Origin in ['UFA','HRG'] and Segments[0].Destination in ['UFA','HRG'] or Segments[0].Origin in ['EGO','CUN'] and Segments[0].Destination in ['EGO','CUN'] or Segments[0].Origin in ['KUF','HRG'] and Segments[0].Destination in ['KUF','HRG'] or Segments[0].Origin in ['CUN','ROV'] and Segments[0].Destination in ['CUN','ROV'] or Segments[0].Origin in ['KBV','KEJ'] and Segments[0].Destination in ['KBV','KEJ'] or Segments[0].Origin in ['NHA','IKT'] and Segments[0].Destination in ['NHA','IKT'] or Segments[0].Origin in ['SSH','KRR'] and Segments[0].Destination in ['SSH','KRR'] or Segments[0].Origin in ['CFU','MOW'] and Segments[0].Destination in ['CFU','MOW'] or Segments[0].Origin in ['MSQ','GPA'] and Segments[0].Destination in ['MSQ','GPA'] or Segments[0].Origin in ['ZTH','MOW'] and Segments[0].Destination in ['ZTH','MOW'] or Segments[0].Origin in ['AER','KJA'] and Segments[0].Destination in ['AER','KJA'] or Segments[0].Origin in ['MOW','CFU'] and Segments[0].Destination in ['MOW','CFU'] or Segments[0].Origin in ['BKK','SCW'] and Segments[0].Destination in ['BKK','SCW'] or Segments[0].Origin in ['PUJ','OGZ'] and Segments[0].Destination in ['PUJ','OGZ'] or Segments[0].Origin in ['AMM','MOW'] and Segments[0].Destination in ['AMM','MOW'] or Segments[0].Origin in ['OVB','TOF'] and Segments[0].Destination in ['OVB','TOF'] or Segments[0].Origin in ['SGN','KZN'] and Segments[0].Destination in ['SGN','KZN'] or Segments[0].Origin in ['VOG','AER'] and Segments[0].Destination in ['VOG','AER'] or Segments[0].Origin in ['VRA','SVX'] and Segments[0].Destination in ['VRA','SVX'] or Segments[0].Origin in ['DXB','SVX'] and Segments[0].Destination in ['DXB','SVX'] or Segments[0].Origin in ['HKT','BQS'] and Segments[0].Destination in ['HKT','BQS'] or Segments[0].Origin in ['PUJ','EGO'] and Segments[0].Destination in ['PUJ','EGO'] or Segments[0].Origin in ['DXB','LED'] and Segments[0].Destination in ['DXB','LED'] or Segments[0].Origin in ['ETH','MOW'] and Segments[0].Destination in ['ETH','MOW'] or Segments[0].Origin in ['MOW','KJA'] and Segments[0].Destination in ['MOW','KJA'] or Segments[0].Origin in ['IKT','MOW'] and Segments[0].Destination in ['IKT','MOW'] or Segments[0].Origin in ['KBV','ROV'] and Segments[0].Destination in ['KBV','ROV'] or Segments[0].Origin in ['BKK','REN'] and Segments[0].Destination in ['BKK','REN'] or Segments[0].Origin in ['HKT','PEE'] and Segments[0].Destination in ['HKT','PEE'] or Segments[0].Origin in ['SVX','VRA'] and Segments[0].Destination in ['SVX','VRA'] or Segments[0].Origin in ['BKK','AER'] and Segments[0].Destination in ['BKK','AER'] or Segments[0].Origin in ['ETH','ROV'] and Segments[0].Destination in ['ETH','ROV'] or Segments[0].Origin in ['SGN','SCW'] and Segments[0].Destination in ['SGN','SCW'] or Segments[0].Origin in ['SIP','KUF'] and Segments[0].Destination in ['SIP','KUF'] or Segments[0].Origin in ['CEK','NHA'] and Segments[0].Destination in ['CEK','NHA'] or Segments[0].Origin in ['AQJ','KRR'] and Segments[0].Destination in ['AQJ','KRR'] or Segments[0].Origin in ['KBV','MOW'] and Segments[0].Destination in ['KBV','MOW'] or Segments[0].Origin in ['BHK','MOW'] and Segments[0].Destination in ['BHK','MOW'] or Segments[0].Origin in ['BKK','PEE'] and Segments[0].Destination in ['BKK','PEE'] or Segments[0].Origin in ['MOW','BAX'] and Segments[0].Destination in ['MOW','BAX'] or Segments[0].Origin in ['GPA','MOW'] and Segments[0].Destination in ['GPA','MOW'] or Segments[0].Origin in ['RIX','MOW'] and Segments[0].Destination in ['RIX','MOW'] or Segments[0].Origin in ['DXB','NBC'] and Segments[0].Destination in ['DXB','NBC'] or Segments[0].Origin in ['PUJ','OVB'] and Segments[0].Destination in ['PUJ','OVB'] or Segments[0].Origin in ['ETH','CEK'] and Segments[0].Destination in ['ETH','CEK'] or Segments[0].Origin in ['KRR','ETH'] and Segments[0].Destination in ['KRR','ETH'] or Segments[0].Origin in ['HKT','UUD'] and Segments[0].Destination in ['HKT','UUD'] or Segments[0].Origin in ['TOF','VRA'] and Segments[0].Destination in ['TOF','VRA'] or Segments[0].Origin in ['MOW','SKG'] and Segments[0].Destination in ['MOW','SKG'] or Segments[0].Origin in ['BTK','OVB'] and Segments[0].Destination in ['BTK','OVB'] or Segments[0].Origin in ['KRR','LCA'] and Segments[0].Destination in ['KRR','LCA'] or Segments[0].Origin in ['OGZ','CUN'] and Segments[0].Destination in ['OGZ','CUN'] or Segments[0].Origin in ['PUJ','KGD'] and Segments[0].Destination in ['PUJ','KGD'] or Segments[0].Origin in ['USM','OVB'] and Segments[0].Destination in ['USM','OVB'] or Segments[0].Origin in ['MOW','SHE'] and Segments[0].Destination in ['MOW','SHE'] or Segments[0].Origin in ['RTW','VRA'] and Segments[0].Destination in ['RTW','VRA'] or Segments[0].Origin in ['SHJ','VOZ'] and Segments[0].Destination in ['SHJ','VOZ'] or Segments[0].Origin in ['SSH','VOG'] and Segments[0].Destination in ['SSH','VOG'] or Segments[0].Origin in ['DXB','NOZ'] and Segments[0].Destination in ['DXB','NOZ'] or Segments[0].Origin in ['SGN','SGC'] and Segments[0].Destination in ['SGN','SGC'] or Segments[0].Origin in ['VVO','NHA'] and Segments[0].Destination in ['VVO','NHA'] or Segments[0].Origin in ['CUN','KZN'] and Segments[0].Destination in ['CUN','KZN'] or Segments[0].Origin in ['AYT','SVX'] and Segments[0].Destination in ['AYT','SVX'] or Segments[0].Origin in ['CUN','KGD'] and Segments[0].Destination in ['CUN','KGD'] or Segments[0].Origin in ['KBV','KZN'] and Segments[0].Destination in ['KBV','KZN'] or Segments[0].Origin in ['VRN','MOW'] and Segments[0].Destination in ['VRN','MOW'] or Segments[0].Origin in ['OVB','UUD'] and Segments[0].Destination in ['OVB','UUD'] or Segments[0].Origin in ['USM','TJM'] and Segments[0].Destination in ['USM','TJM'] or Segments[0].Origin in ['HRG','MMK'] and Segments[0].Destination in ['HRG','MMK'] or Segments[0].Origin in ['KUF','SSH'] and Segments[0].Destination in ['KUF','SSH'] or Segments[0].Origin in ['AER','LED'] and Segments[0].Destination in ['AER','LED'] or Segments[0].Origin in ['SGN','ROV'] and Segments[0].Destination in ['SGN','ROV'] or Segments[0].Origin in ['KZN','CUN'] and Segments[0].Destination in ['KZN','CUN'] or Segments[0].Origin in ['VRA','NBC'] and Segments[0].Destination in ['VRA','NBC'] or Segments[0].Origin in ['KUF','CUN'] and Segments[0].Destination in ['KUF','CUN'] or Segments[0].Origin in ['SSH','SGC'] and Segments[0].Destination in ['SSH','SGC'] or Segments[0].Origin in ['VRA','OVB'] and Segments[0].Destination in ['VRA','OVB'] or Segments[0].Origin in ['ODS','SKG'] and Segments[0].Destination in ['ODS','SKG'] or Segments[0].Origin in ['AMM','LED'] and Segments[0].Destination in ['AMM','LED'] or Segments[0].Origin in ['RTW','PUJ'] and Segments[0].Destination in ['RTW','PUJ'] or Segments[0].Origin in ['BKK','NJC'] and Segments[0].Destination in ['BKK','NJC'] or Segments[0].Origin in ['CUN','KRR'] and Segments[0].Destination in ['CUN','KRR'] or Segments[0].Origin in ['MRV','SSH'] and Segments[0].Destination in ['MRV','SSH'] or Segments[0].Origin in ['SGC','HRG'] and Segments[0].Destination in ['SGC','HRG'] or Segments[0].Origin in ['KZN','SKG'] and Segments[0].Destination in ['KZN','SKG'] or Segments[0].Origin in ['UFA','MOW'] and Segments[0].Destination in ['UFA','MOW'] or Segments[0].Origin in ['ROM','MOW'] and Segments[0].Destination in ['ROM','MOW'] or Segments[0].Origin in ['NBC','PUJ'] and Segments[0].Destination in ['NBC','PUJ'] or Segments[0].Origin in ['KHV','MOW'] and Segments[0].Destination in ['KHV','MOW'] or Segments[0].Origin in ['VRA','CEK'] and Segments[0].Destination in ['VRA','CEK'] or Segments[0].Origin in ['VRA','KEJ'] and Segments[0].Destination in ['VRA','KEJ'] or Segments[0].Origin in ['MOW','VVO'] and Segments[0].Destination in ['MOW','VVO'] or Segments[0].Origin in ['TOF','CUN'] and Segments[0].Destination in ['TOF','CUN'] or Segments[0].Origin in ['OVB','SKG'] and Segments[0].Destination in ['OVB','SKG'] or Segments[0].Origin in ['CUN','VOG'] and Segments[0].Destination in ['CUN','VOG'] or Segments[0].Origin in ['BKK','VOZ'] and Segments[0].Destination in ['BKK','VOZ'] or Segments[0].Origin in ['ROV','ETH'] and Segments[0].Destination in ['ROV','ETH'] or Segments[0].Origin in ['HTA','NHA'] and Segments[0].Destination in ['HTA','NHA'] or Segments[0].Origin in ['GOJ','VRA'] and Segments[0].Destination in ['GOJ','VRA'] or Segments[0].Origin in ['MOW','VRN'] and Segments[0].Destination in ['MOW','VRN'] or Segments[0].Origin in ['KZN','HRG'] and Segments[0].Destination in ['KZN','HRG'] or Segments[0].Origin in ['NHA','BAX'] and Segments[0].Destination in ['NHA','BAX'] or Segments[0].Origin in ['VRA','ASF'] and Segments[0].Destination in ['VRA','ASF'] or Segments[0].Origin in ['GOJ','SKG'] and Segments[0].Destination in ['GOJ','SKG'] or Segments[0].Origin in ['SKG','LWO'] and Segments[0].Destination in ['SKG','LWO'] or Segments[0].Origin in ['MRV','CUN'] and Segments[0].Destination in ['MRV','CUN'] or Segments[0].Origin in ['SOF','MOW'] and Segments[0].Destination in ['SOF','MOW'] or Segments[0].Origin in ['BAX','VRA'] and Segments[0].Destination in ['BAX','VRA'] or Segments[0].Origin in ['SSH','MRV'] and Segments[0].Destination in ['SSH','MRV'] or Segments[0].Origin in ['KRR','LED'] and Segments[0].Destination in ['KRR','LED'] or Segments[0].Origin in ['NHA','REN'] and Segments[0].Destination in ['NHA','REN'] or Segments[0].Origin in ['ATH','MOW'] and Segments[0].Destination in ['ATH','MOW'] or Segments[0].Origin in ['KZN','VRA'] and Segments[0].Destination in ['KZN','VRA'] or Segments[0].Origin in ['HRG','VOZ'] and Segments[0].Destination in ['HRG','VOZ'] or Segments[0].Origin in ['SGN','KUF'] and Segments[0].Destination in ['SGN','KUF'] or Segments[0].Origin in ['LED','CFU'] and Segments[0].Destination in ['LED','CFU'] or Segments[0].Origin in ['SGN','MRV'] and Segments[0].Destination in ['SGN','MRV'] or Segments[0].Origin in ['CUN','EGO'] and Segments[0].Destination in ['CUN','EGO'] or Segments[0].Origin in ['KJA','AER'] and Segments[0].Destination in ['KJA','AER'] or Segments[0].Origin in ['VRA','SCW'] and Segments[0].Destination in ['VRA','SCW'] or Segments[0].Origin in ['BQS','NHA'] and Segments[0].Destination in ['BQS','NHA'] or Segments[0].Origin in ['KGD','SSH'] and Segments[0].Destination in ['KGD','SSH'] or Segments[0].Origin in ['BKK','KRR'] and Segments[0].Destination in ['BKK','KRR'] or Segments[0].Origin in ['DXB','OVB'] and Segments[0].Destination in ['DXB','OVB'] or Segments[0].Origin in ['KRR','HRG'] and Segments[0].Destination in ['KRR','HRG'] or Segments[0].Origin in ['VRA','OMS'] and Segments[0].Destination in ['VRA','OMS'] or Segments[0].Origin in ['BKK','MRV'] and Segments[0].Destination in ['BKK','MRV'] or Segments[0].Origin in ['IKT','PUJ'] and Segments[0].Destination in ['IKT','PUJ'] or Segments[0].Origin in ['KZN','PUJ'] and Segments[0].Destination in ['KZN','PUJ'] or Segments[0].Origin in ['BKK','LED'] and Segments[0].Destination in ['BKK','LED'] or Segments[0].Origin in ['SGN','LED'] and Segments[0].Destination in ['SGN','LED'] or Segments[0].Origin in ['NHA','CEK'] and Segments[0].Destination in ['NHA','CEK'] or Segments[0].Origin in ['KJA','SSH'] and Segments[0].Destination in ['KJA','SSH'] or Segments[0].Origin in ['CUN','MOW'] and Segments[0].Destination in ['CUN','MOW'] or Segments[0].Origin in ['UUD','NHA'] and Segments[0].Destination in ['UUD','NHA'] or Segments[0].Origin in ['KUF','ETH'] and Segments[0].Destination in ['KUF','ETH'] or Segments[0].Origin in ['HKT','REN'] and Segments[0].Destination in ['HKT','REN'] or Segments[0].Origin in ['BKK','MOW'] and Segments[0].Destination in ['BKK','MOW'] or Segments[0].Origin in ['BKK','UUD'] and Segments[0].Destination in ['BKK','UUD'] or Segments[0].Origin in ['CUN','OVB'] and Segments[0].Destination in ['CUN','OVB'] or Segments[0].Origin in ['SVX','SSH'] and Segments[0].Destination in ['SVX','SSH'] or Segments[0].Origin in ['LED','ETH'] and Segments[0].Destination in ['LED','ETH'] or Segments[0].Origin in ['MSQ','CFU'] and Segments[0].Destination in ['MSQ','CFU'] or Segments[0].Origin in ['KGD','PUJ'] and Segments[0].Destination in ['KGD','PUJ'] or Segments[0].Origin in ['OVB','AER'] and Segments[0].Destination in ['OVB','AER'] or Segments[0].Origin in ['OMS','NHA'] and Segments[0].Destination in ['OMS','NHA'] or Segments[0].Origin in ['PUJ','GOJ'] and Segments[0].Destination in ['PUJ','GOJ'] or Segments[0].Origin in ['NHA','TOF'] and Segments[0].Destination in ['NHA','TOF'] or Segments[0].Origin in ['TDX','BAX'] and Segments[0].Destination in ['TDX','BAX'] or Segments[0].Origin in ['UTP','KJA'] and Segments[0].Destination in ['UTP','KJA'] or Segments[0].Origin in ['BKK','KHV'] and Segments[0].Destination in ['BKK','KHV'] or Segments[0].Origin in ['NHA','BQS'] and Segments[0].Destination in ['NHA','BQS'] or Segments[0].Origin in ['CMF','MOW'] and Segments[0].Destination in ['CMF','MOW'] or Segments[0].Origin in ['BER','MOW'] and Segments[0].Destination in ['BER','MOW'] or Segments[0].Origin in ['SGN','KHV'] and Segments[0].Destination in ['SGN','KHV'] or Segments[0].Origin in ['DXB','NJC'] and Segments[0].Destination in ['DXB','NJC'] or Segments[0].Origin in ['IKT','VRA'] and Segments[0].Destination in ['IKT','VRA'] or Segments[0].Origin in ['TAS','MOW'] and Segments[0].Destination in ['TAS','MOW'] or Segments[0].Origin in ['GOJ','AYT'] and Segments[0].Destination in ['GOJ','AYT'] or Segments[0].Origin in ['VRA','GOJ'] and Segments[0].Destination in ['VRA','GOJ'] or Segments[0].Origin in ['MOW','BQS'] and Segments[0].Destination in ['MOW','BQS'] or Segments[0].Origin in ['NOZ','VRA'] and Segments[0].Destination in ['NOZ','VRA'] or Segments[0].Origin in ['PUJ','CEK'] and Segments[0].Destination in ['PUJ','CEK'] or Segments[0].Origin in ['USM','BAX'] and Segments[0].Destination in ['USM','BAX'] or Segments[0].Origin in ['ROV','VRN'] and Segments[0].Destination in ['ROV','VRN'] or Segments[0].Origin in ['OVB','CUN'] and Segments[0].Destination in ['OVB','CUN'] or Segments[0].Origin in ['OVB','MOW'] and Segments[0].Destination in ['OVB','MOW'] or Segments[0].Origin in ['SKG','ROV'] and Segments[0].Destination in ['SKG','ROV'] or Segments[0].Origin in ['MOW','BKK'] and Segments[0].Destination in ['MOW','BKK'] or Segments[0].Origin in ['BKK','IKT'] and Segments[0].Destination in ['BKK','IKT'] or Segments[0].Origin in ['TDX','SGC'] and Segments[0].Destination in ['TDX','SGC'] or Segments[0].Origin in ['ROV','VRA'] and Segments[0].Destination in ['ROV','VRA'] or Segments[0].Origin in ['BKK','TOF'] and Segments[0].Destination in ['BKK','TOF'] or Segments[0].Origin in ['CUN','MRV'] and Segments[0].Destination in ['CUN','MRV'] or Segments[0].Origin in ['ZTH','MSQ'] and Segments[0].Destination in ['ZTH','MSQ'] or Segments[0].Origin in ['MOW','CMF'] and Segments[0].Destination in ['MOW','CMF'] or Segments[0].Origin in ['CUN','PEE'] and Segments[0].Destination in ['CUN','PEE'] or Segments[0].Origin in ['CEK','HRG'] and Segments[0].Destination in ['CEK','HRG'] or Segments[0].Origin in ['HRG','KRR'] and Segments[0].Destination in ['HRG','KRR'] or Segments[0].Origin in ['VAR','LED'] and Segments[0].Destination in ['VAR','LED'] or Segments[0].Origin in ['NBC','SSH'] and Segments[0].Destination in ['NBC','SSH'] or Segments[0].Origin in ['PUJ','AER'] and Segments[0].Destination in ['PUJ','AER'] or Segments[0].Origin in ['SIP','SVX'] and Segments[0].Destination in ['SIP','SVX'] or Segments[0].Origin in ['ROV','NHA'] and Segments[0].Destination in ['ROV','NHA'] or Segments[0].Origin in ['CUN','IKT'] and Segments[0].Destination in ['CUN','IKT'] or Segments[0].Origin in ['OVB','VRA'] and Segments[0].Destination in ['OVB','VRA'] or Segments[0].Origin in ['MOW','OVB'] and Segments[0].Destination in ['MOW','OVB'] or Segments[0].Origin in ['UUD','OVB'] and Segments[0].Destination in ['UUD','OVB'] or Segments[0].Origin in ['KRR','OVB'] and Segments[0].Destination in ['KRR','OVB'] or Segments[0].Origin in ['TJM','PUJ'] and Segments[0].Destination in ['TJM','PUJ'] or Segments[0].Origin in ['PEE','HRG'] and Segments[0].Destination in ['PEE','HRG'] or Segments[0].Origin in ['KZN','AYT'] and Segments[0].Destination in ['KZN','AYT'] or Segments[0].Origin in ['GVA','MOW'] and Segments[0].Destination in ['GVA','MOW'] or Segments[0].Origin in ['CUN','OGZ'] and Segments[0].Destination in ['CUN','OGZ'] or Segments[0].Origin in ['MUC','MOW'] and Segments[0].Destination in ['MUC','MOW'] or Segments[0].Origin in ['VOZ','SSH'] and Segments[0].Destination in ['VOZ','SSH'] or Segments[0].Origin in ['AER','OVB'] and Segments[0].Destination in ['AER','OVB'] or Segments[0].Origin in ['HRG','KEJ'] and Segments[0].Destination in ['HRG','KEJ'] or Segments[0].Origin in ['TJM','VRA'] and Segments[0].Destination in ['TJM','VRA'] or Segments[0].Origin in ['HKT','BAX'] and Segments[0].Destination in ['HKT','BAX'] or Segments[0].Origin in ['KUF','AER'] and Segments[0].Destination in ['KUF','AER'] or Segments[0].Origin in ['SGN','HTA'] and Segments[0].Destination in ['SGN','HTA'] or Segments[0].Origin in ['SSH','UFA'] and Segments[0].Destination in ['SSH','UFA'] or Segments[0].Origin in ['SHJ','MOW'] and Segments[0].Destination in ['SHJ','MOW'] or Segments[0].Origin in ['SSH','KZN'] and Segments[0].Destination in ['SSH','KZN'] or Segments[0].Origin in ['SVX','PUJ'] and Segments[0].Destination in ['SVX','PUJ'] or Segments[0].Origin in ['PRG','MOW'] and Segments[0].Destination in ['PRG','MOW'] or Segments[0].Origin in ['VOZ','VRA'] and Segments[0].Destination in ['VOZ','VRA'] or Segments[0].Origin in ['AER','MOW'] and Segments[0].Destination in ['AER','MOW'] or Segments[0].Origin in ['SSH','OMS'] and Segments[0].Destination in ['SSH','OMS'] or Segments[0].Origin in ['SSH','SCW'] and Segments[0].Destination in ['SSH','SCW'] or Segments[0].Origin in ['CUN','MCX'] and Segments[0].Destination in ['CUN','MCX'] or Segments[0].Origin in ['MMK','HRG'] and Segments[0].Destination in ['MMK','HRG'] or Segments[0].Origin in ['LED','SOF'] and Segments[0].Destination in ['LED','SOF'] or Segments[0].Origin in ['KBV','UFA'] and Segments[0].Destination in ['KBV','UFA'] or Segments[0].Origin in ['DJE','MOW'] and Segments[0].Destination in ['DJE','MOW'] or Segments[0].Origin in ['NJC','VRA'] and Segments[0].Destination in ['NJC','VRA'] or Segments[0].Origin in ['YKS','NHA'] and Segments[0].Destination in ['YKS','NHA'] or Segments[0].Origin in ['SSH','MMK'] and Segments[0].Destination in ['SSH','MMK'] or Segments[0].Origin in ['PUJ','TJM'] and Segments[0].Destination in ['PUJ','TJM'] or Segments[0].Origin in ['TOF','NHA'] and Segments[0].Destination in ['TOF','NHA'] or Segments[0].Origin in ['SGN','PEE'] and Segments[0].Destination in ['SGN','PEE'] or Segments[0].Origin in ['NOZ','CUN'] and Segments[0].Destination in ['NOZ','CUN'] or Segments[0].Origin in ['PEE','PUJ'] and Segments[0].Destination in ['PEE','PUJ'] or Segments[0].Origin in ['SVX','NHA'] and Segments[0].Destination in ['SVX','NHA'] or Segments[0].Origin in ['ARH','NHA'] and Segments[0].Destination in ['ARH','NHA'] or Segments[0].Origin in ['SCW','NHA'] and Segments[0].Destination in ['SCW','NHA'] or Segments[0].Origin in ['KEJ','SSH'] and Segments[0].Destination in ['KEJ','SSH'] or Segments[0].Origin in ['AER','UFA'] and Segments[0].Destination in ['AER','UFA'] or Segments[0].Origin in ['NHA','MCX'] and Segments[0].Destination in ['NHA','MCX'] or Segments[0].Origin in ['CUN','LED'] and Segments[0].Destination in ['CUN','LED'] or Segments[0].Origin in ['MOW','FEG'] and Segments[0].Destination in ['MOW','FEG'] or Segments[0].Origin in ['MOW','SVX'] and Segments[0].Destination in ['MOW','SVX'] or Segments[0].Origin in ['KBV','SGC'] and Segments[0].Destination in ['KBV','SGC'] or Segments[0].Origin in ['VRA','KRR'] and Segments[0].Destination in ['VRA','KRR'] or Segments[0].Origin in ['SKG','KRR'] and Segments[0].Destination in ['SKG','KRR'] or Segments[0].Origin in ['NJC','PUJ'] and Segments[0].Destination in ['NJC','PUJ'] or Segments[0].Origin in ['MSQ','ZTH'] and Segments[0].Destination in ['MSQ','ZTH'] or Segments[0].Origin in ['SKG','VOG'] and Segments[0].Destination in ['SKG','VOG'] or Segments[0].Origin in ['KJA','CUN'] and Segments[0].Destination in ['KJA','CUN'] or Segments[0].Origin in ['DXB','GOJ'] and Segments[0].Destination in ['DXB','GOJ'] or Segments[0].Origin in ['SGN','BAX'] and Segments[0].Destination in ['SGN','BAX'] or Segments[0].Origin in ['KUF','AYT'] and Segments[0].Destination in ['KUF','AYT'] or Segments[0].Origin in ['ETH','KRR'] and Segments[0].Destination in ['ETH','KRR'] or Segments[0].Origin in ['IKT','NHA'] and Segments[0].Destination in ['IKT','NHA'] or Segments[0].Origin in ['ROV','HRG'] and Segments[0].Destination in ['ROV','HRG'] or Segments[0].Origin in ['PUJ','IKT'] and Segments[0].Destination in ['PUJ','IKT'] or Segments[0].Origin in ['TIV','MOW'] and Segments[0].Destination in ['TIV','MOW'] or Segments[0].Origin in ['PUJ','MOW'] and Segments[0].Destination in ['PUJ','MOW'] or Segments[0].Origin in ['CEK','VRA'] and Segments[0].Destination in ['CEK','VRA'] or Segments[0].Origin in ['EGO','PUJ'] and Segments[0].Destination in ['EGO','PUJ'] or Segments[0].Origin in ['TDX','IKT'] and Segments[0].Destination in ['TDX','IKT'] or Segments[0].Origin in ['SKG','KGD'] and Segments[0].Destination in ['SKG','KGD'] or Segments[0].Origin in ['SGN','UFA'] and Segments[0].Destination in ['SGN','UFA'] or Segments[0].Origin in ['MOW','BOJ'] and Segments[0].Destination in ['MOW','BOJ'] or Segments[0].Origin in ['NHA','KRR'] and Segments[0].Destination in ['NHA','KRR'] or Segments[0].Origin in ['HKT','KHV'] and Segments[0].Destination in ['HKT','KHV'] or Segments[0].Origin in ['RIX','SKG'] and Segments[0].Destination in ['RIX','SKG'] or Segments[0].Origin in ['SIP','KRR'] and Segments[0].Destination in ['SIP','KRR'] or Segments[0].Origin in ['AAQ','VRA'] and Segments[0].Destination in ['AAQ','VRA'] or Segments[0].Origin in ['VOZ','HRG'] and Segments[0].Destination in ['VOZ','HRG'] or Segments[0].Origin in ['CFU','LED'] and Segments[0].Destination in ['CFU','LED'] or Segments[0].Origin in ['KBV','BQS'] and Segments[0].Destination in ['KBV','BQS'] or Segments[0].Origin in ['BKK','NBC'] and Segments[0].Destination in ['BKK','NBC'] or Segments[0].Origin in ['SSH','GOJ'] and Segments[0].Destination in ['SSH','GOJ'] or Segments[0].Origin in ['LED','OVB'] and Segments[0].Destination in ['LED','OVB'] or Segments[0].Origin in ['NHA','UUD'] and Segments[0].Destination in ['NHA','UUD'] or Segments[0].Origin in ['CUN','UFA'] and Segments[0].Destination in ['CUN','UFA'] or Segments[0].Origin in ['MMK','SSH'] and Segments[0].Destination in ['MMK','SSH'] or Segments[0].Origin in ['MOW','PKC'] and Segments[0].Destination in ['MOW','PKC'] or Segments[0].Origin in ['SKG','ODS'] and Segments[0].Destination in ['SKG','ODS'] or Segments[0].Origin in ['UFA','SKG'] and Segments[0].Destination in ['UFA','SKG'] or Segments[0].Origin in ['UFA','AER'] and Segments[0].Destination in ['UFA','AER'] or Segments[0].Origin in ['VRA','NOZ'] and Segments[0].Destination in ['VRA','NOZ'] or Segments[0].Origin in ['NHA','MOW'] and Segments[0].Destination in ['NHA','MOW'] or Segments[0].Origin in ['HKT','NOZ'] and Segments[0].Destination in ['HKT','NOZ'] or Segments[0].Origin in ['MCX','VRA'] and Segments[0].Destination in ['MCX','VRA'] or Segments[0].Origin in ['SIP','LED'] and Segments[0].Destination in ['SIP','LED'] or Segments[0].Origin in ['MOW','BGY'] and Segments[0].Destination in ['MOW','BGY'] or Segments[0].Origin in ['HKT','EGO'] and Segments[0].Destination in ['HKT','EGO'] or Segments[0].Origin in ['KZN','AER'] and Segments[0].Destination in ['KZN','AER'] or Segments[0].Origin in ['NHA','OVB'] and Segments[0].Destination in ['NHA','OVB'] or Segments[0].Origin in ['VRA','VOZ'] and Segments[0].Destination in ['VRA','VOZ'] or Segments[0].Origin in ['OVB','LED'] and Segments[0].Destination in ['OVB','LED'] or Segments[0].Origin in ['NBC','CUN'] and Segments[0].Destination in ['NBC','CUN'] or Segments[0].Origin in ['VRA','KGD'] and Segments[0].Destination in ['VRA','KGD'] or Segments[0].Origin in ['CUN','CEK'] and Segments[0].Destination in ['CUN','CEK'] or Segments[0].Origin in ['VOZ','CUN'] and Segments[0].Destination in ['VOZ','CUN'] or Segments[0].Origin in ['DYR','MOW'] and Segments[0].Destination in ['DYR','MOW'] or Segments[0].Origin in ['MOW','SOF'] and Segments[0].Destination in ['MOW','SOF'] or Segments[0].Origin in ['LED','PRG'] and Segments[0].Destination in ['LED','PRG'] or Segments[0].Origin in ['PKC','NHA'] and Segments[0].Destination in ['PKC','NHA'] or Segments[0].Origin in ['BKK','TJM'] and Segments[0].Destination in ['BKK','TJM'] or Segments[0].Origin in ['NHA','OMS'] and Segments[0].Destination in ['NHA','OMS'] or Segments[0].Origin in ['DXB','BAX'] and Segments[0].Destination in ['DXB','BAX'] or Segments[0].Origin in ['OVB','HRG'] and Segments[0].Destination in ['OVB','HRG'] or Segments[0].Origin in ['AYT','KUF'] and Segments[0].Destination in ['AYT','KUF'] or Segments[0].Origin in ['HKT','CEK'] and Segments[0].Destination in ['HKT','CEK'] or Segments[0].Origin in ['GRV','MOW'] and Segments[0].Destination in ['GRV','MOW'] or Segments[0].Origin in ['IEV','ATH'] and Segments[0].Destination in ['IEV','ATH'] or Segments[0].Origin in ['OGZ','NHA'] and Segments[0].Destination in ['OGZ','NHA'] or Segments[0].Origin in ['ROV','SSH'] and Segments[0].Destination in ['ROV','SSH'] or Segments[0].Origin in ['SKG','UFA'] and Segments[0].Destination in ['SKG','UFA'] or Segments[0].Origin in ['CUN','BAX'] and Segments[0].Destination in ['CUN','BAX'] or Segments[0].Origin in ['SZG','MOW'] and Segments[0].Destination in ['SZG','MOW'] or Segments[0].Origin in ['HKT','KGD'] and Segments[0].Destination in ['HKT','KGD'] or Segments[0].Origin in ['ROV','SKG'] and Segments[0].Destination in ['ROV','SKG'] or Segments[0].Origin in ['USM','SVX'] and Segments[0].Destination in ['USM','SVX'] or Segments[0].Origin in ['KBV','BAX'] and Segments[0].Destination in ['KBV','BAX'] or Segments[0].Origin in ['BQS','MOW'] and Segments[0].Destination in ['BQS','MOW'] or Segments[0].Origin in ['SSH','KEJ'] and Segments[0].Destination in ['SSH','KEJ'] or Segments[0].Origin in ['SIP','UFA'] and Segments[0].Destination in ['SIP','UFA'] or Segments[0].Origin in ['CUN','YKS'] and Segments[0].Destination in ['CUN','YKS'] or Segments[0].Origin in ['GOJ','NHA'] and Segments[0].Destination in ['GOJ','NHA'] or Segments[0].Origin in ['MOW','PUJ'] and Segments[0].Destination in ['MOW','PUJ'] or Segments[0].Origin in ['NHA','LED'] and Segments[0].Destination in ['NHA','LED'] or Segments[0].Origin in ['HKT','VOZ'] and Segments[0].Destination in ['HKT','VOZ'] or Segments[0].Origin in ['OMS','VRA'] and Segments[0].Destination in ['OMS','VRA'] or Segments[0].Origin in ['OVB','BQS'] and Segments[0].Destination in ['OVB','BQS'] or Segments[0].Origin in ['BKK','GOJ'] and Segments[0].Destination in ['BKK','GOJ'] or Segments[0].Origin in ['HKT','ASF'] and Segments[0].Destination in ['HKT','ASF'] or Segments[0].Origin in ['LED','PUJ'] and Segments[0].Destination in ['LED','PUJ'] or Segments[0].Origin in ['CUN','KUF'] and Segments[0].Destination in ['CUN','KUF'] or Segments[0].Origin in ['MOW','LCA'] and Segments[0].Destination in ['MOW','LCA'] or Segments[0].Origin in ['CUN','KEJ'] and Segments[0].Destination in ['CUN','KEJ'] or Segments[0].Origin in ['LWO','SKG'] and Segments[0].Destination in ['LWO','SKG'] or Segments[0].Origin in ['HRG','SVX'] and Segments[0].Destination in ['HRG','SVX'] or Segments[0].Origin in ['TCI','MOW'] and Segments[0].Destination in ['TCI','MOW'] or Segments[0].Origin in ['SIP','AER'] and Segments[0].Destination in ['SIP','AER'] or Segments[0].Origin in ['SGN','TJM'] and Segments[0].Destination in ['SGN','TJM'] or Segments[0].Origin in ['PUJ','VOG'] and Segments[0].Destination in ['PUJ','VOG'] or Segments[0].Origin in ['UFA','SSH'] and Segments[0].Destination in ['UFA','SSH'] or Segments[0].Origin in ['MIL','MOW'] and Segments[0].Destination in ['MIL','MOW'] or Segments[0].Origin in ['AER','PUJ'] and Segments[0].Destination in ['AER','PUJ'] or Segments[0].Origin in ['NHA','HTA'] and Segments[0].Destination in ['NHA','HTA'] or Segments[0].Origin in ['BQS','OVB'] and Segments[0].Destination in ['BQS','OVB'] or Segments[0].Origin in ['USM','MOW'] and Segments[0].Destination in ['USM','MOW'] or Segments[0].Origin in ['KBV','IKT'] and Segments[0].Destination in ['KBV','IKT'] or Segments[0].Origin in ['HKT','UFA'] and Segments[0].Destination in ['HKT','UFA'] or Segments[0].Origin in ['MOW','KHV'] and Segments[0].Destination in ['MOW','KHV'] or Segments[0].Origin in ['UTP','EGO'] and Segments[0].Destination in ['UTP','EGO'] or Segments[0].Origin in ['DXB','HTA'] and Segments[0].Destination in ['DXB','HTA'] or Segments[0].Origin in ['SGN','OMS'] and Segments[0].Destination in ['SGN','OMS'] or Segments[0].Origin in ['MOW','AER'] and Segments[0].Destination in ['MOW','AER'] or Segments[0].Origin in ['HTA','PUJ'] and Segments[0].Destination in ['HTA','PUJ'] or Segments[0].Origin in ['KJA','NHA'] and Segments[0].Destination in ['KJA','NHA'] or Segments[0].Origin in ['HKT','OMS'] and Segments[0].Destination in ['HKT','OMS'] or Segments[0].Origin in ['OGZ','PUJ'] and Segments[0].Destination in ['OGZ','PUJ'] or Segments[0].Origin in ['PUJ','UFA'] and Segments[0].Destination in ['PUJ','UFA'] or Segments[0].Origin in ['DXB','KUF'] and Segments[0].Destination in ['DXB','KUF'] or Segments[0].Origin in ['BKK','MCX'] and Segments[0].Destination in ['BKK','MCX'] or Segments[0].Origin in ['NHA','PKC'] and Segments[0].Destination in ['NHA','PKC'] or Segments[0].Origin in ['CUN','KJA'] and Segments[0].Destination in ['CUN','KJA'] or Segments[0].Origin in ['KRR','PUJ'] and Segments[0].Destination in ['KRR','PUJ'] or Segments[0].Origin in ['HKT','IKT'] and Segments[0].Destination in ['HKT','IKT'] or Segments[0].Origin in ['DXB','ROV'] and Segments[0].Destination in ['DXB','ROV'] or Segments[0].Origin in ['DXB','TJM'] and Segments[0].Destination in ['DXB','TJM'] or Segments[0].Origin in ['NHA','KJA'] and Segments[0].Destination in ['NHA','KJA'] or Segments[0].Origin in ['USM','OMS'] and Segments[0].Destination in ['USM','OMS'] or Segments[0].Origin in ['KHV','NHA'] and Segments[0].Destination in ['KHV','NHA'] or Segments[0].Origin in ['HRG','KGD'] and Segments[0].Destination in ['HRG','KGD'] or Segments[0].Origin in ['VOG','SSH'] and Segments[0].Destination in ['VOG','SSH'] or Segments[0].Origin in ['MCX','PUJ'] and Segments[0].Destination in ['MCX','PUJ'] or Segments[0].Origin in ['MOW','TIV'] and Segments[0].Destination in ['MOW','TIV'] or Segments[0].Origin in ['DXB','KRR'] and Segments[0].Destination in ['DXB','KRR'] or Segments[0].Origin in ['DNK','SKG'] and Segments[0].Destination in ['DNK','SKG'] or Segments[0].Origin in ['HKT','KZN'] and Segments[0].Destination in ['HKT','KZN'] or Segments[0].Origin in ['USM','LED'] and Segments[0].Destination in ['USM','LED'] or Segments[0].Origin in ['HKT','MRV'] and Segments[0].Destination in ['HKT','MRV'] or Segments[0].Origin in ['HKT','TOF'] and Segments[0].Destination in ['HKT','TOF'] or Segments[0].Origin in ['MOW','UFA'] and Segments[0].Destination in ['MOW','UFA'] or Segments[0].Origin in ['DXB','KEJ'] and Segments[0].Destination in ['DXB','KEJ'] or Segments[0].Origin in ['YKS','CUN'] and Segments[0].Destination in ['YKS','CUN'] or Segments[0].Origin in ['KEJ','HRG'] and Segments[0].Destination in ['KEJ','HRG'] or Segments[0].Origin in ['MCX','NHA'] and Segments[0].Destination in ['MCX','NHA'] or Segments[0].Origin in ['NHA','SCW'] and Segments[0].Destination in ['NHA','SCW'] or Segments[0].Origin in ['DXB','MRV'] and Segments[0].Destination in ['DXB','MRV'] or Segments[0].Origin in ['BKK','OGZ'] and Segments[0].Destination in ['BKK','OGZ'] or Segments[0].Origin in ['UTP','PEE'] and Segments[0].Destination in ['UTP','PEE'] or Segments[0].Origin in ['USM','ROV'] and Segments[0].Destination in ['USM','ROV'] or Segments[0].Origin in ['VRA','YKS'] and Segments[0].Destination in ['VRA','YKS'] or Segments[0].Origin in ['SHE','MOW'] and Segments[0].Destination in ['SHE','MOW'] or Segments[0].Origin in ['MOW','TSN'] and Segments[0].Destination in ['MOW','TSN'] or Segments[0].Origin in ['TOF','OVB'] and Segments[0].Destination in ['TOF','OVB'] or Segments[0].Origin in ['NHA','KEJ'] and Segments[0].Destination in ['NHA','KEJ'] or Segments[0].Origin in ['KGD','CUN'] and Segments[0].Destination in ['KGD','CUN'] or Segments[0].Origin in ['UTP','KUF'] and Segments[0].Destination in ['UTP','KUF'] or Segments[0].Origin in ['SIP','KZN'] and Segments[0].Destination in ['SIP','KZN'] or Segments[0].Origin in ['CUN','SCW'] and Segments[0].Destination in ['CUN','SCW'] or Segments[0].Origin in ['SHJ','REN'] and Segments[0].Destination in ['SHJ','REN'] or Segments[0].Origin in ['SGN','KRR'] and Segments[0].Destination in ['SGN','KRR'] or Segments[0].Origin in ['KEJ','NHA'] and Segments[0].Destination in ['KEJ','NHA'] or Segments[0].Origin in ['CFU','IEV'] and Segments[0].Destination in ['CFU','IEV'] or Segments[0].Origin in ['MOW','CUN'] and Segments[0].Destination in ['MOW','CUN'] or Segments[0].Origin in ['LCA','MOW'] and Segments[0].Destination in ['LCA','MOW'] or Segments[0].Origin in ['SSH','ROV'] and Segments[0].Destination in ['SSH','ROV'] or Segments[0].Origin in ['BUH','MOW'] and Segments[0].Destination in ['BUH','MOW'] or Segments[0].Origin in ['SGN','BQS'] and Segments[0].Destination in ['SGN','BQS'] or Segments[0].Origin in ['KUF','VRA'] and Segments[0].Destination in ['KUF','VRA'] or Segments[0].Origin in ['NHA','KHV'] and Segments[0].Destination in ['NHA','KHV'] or Segments[0].Origin in ['DXB','TOF'] and Segments[0].Destination in ['DXB','TOF'] or Segments[0].Origin in ['HKT','KUF'] and Segments[0].Destination in ['HKT','KUF'] or Segments[0].Origin in ['EGO','NHA'] and Segments[0].Destination in ['EGO','NHA'] or Segments[0].Origin in ['MOW','BCN'] and Segments[0].Destination in ['MOW','BCN'] or Segments[0].Origin in ['SCW','HRG'] and Segments[0].Destination in ['SCW','HRG'] or Segments[0].Origin in ['BAX','CUN'] and Segments[0].Destination in ['BAX','CUN'] or Segments[0].Origin in ['AYT','PEE'] and Segments[0].Destination in ['AYT','PEE'] or Segments[0].Origin in ['BKK','OMS'] and Segments[0].Destination in ['BKK','OMS'] or Segments[0].Origin in ['LCA','KRR'] and Segments[0].Destination in ['LCA','KRR'] or Segments[0].Origin in ['BKK','CEK'] and Segments[0].Destination in ['BKK','CEK'] or Segments[0].Origin in ['MOW','VRA'] and Segments[0].Destination in ['MOW','VRA'] or Segments[0].Origin in ['LED','ZTH'] and Segments[0].Destination in ['LED','ZTH'] or Segments[0].Origin in ['KEJ','VRA'] and Segments[0].Destination in ['KEJ','VRA'] or Segments[0].Origin in ['MOW','DYR'] and Segments[0].Destination in ['MOW','DYR'] or Segments[0].Origin in ['HKT','YKS'] and Segments[0].Destination in ['HKT','YKS'] or Segments[0].Origin in ['MOW','MIR'] and Segments[0].Destination in ['MOW','MIR'] or Segments[0].Origin in ['TRN','MOW'] and Segments[0].Destination in ['TRN','MOW'] or Segments[0].Origin in ['RVN','MOW'] and Segments[0].Destination in ['RVN','MOW'] or Segments[0].Origin in ['CEK','SSH'] and Segments[0].Destination in ['CEK','SSH'] or Segments[0].Origin in ['ETH','UFA'] and Segments[0].Destination in ['ETH','UFA'] or Segments[0].Origin in ['VRA','UFA'] and Segments[0].Destination in ['VRA','UFA'] or Segments[0].Origin in ['MOW','HER'] and Segments[0].Destination in ['MOW','HER'] or Segments[0].Origin in ['DXB','OMS'] and Segments[0].Destination in ['DXB','OMS'] or Segments[0].Origin in ['VRA','ROV'] and Segments[0].Destination in ['VRA','ROV'] or Segments[0].Origin in ['MRV','PUJ'] and Segments[0].Destination in ['MRV','PUJ'] or Segments[0].Origin in ['NHA','EGO'] and Segments[0].Destination in ['NHA','EGO'] or Segments[0].Origin in ['VRA','TOF'] and Segments[0].Destination in ['VRA','TOF'] or Segments[0].Origin in ['BOJ','LED'] and Segments[0].Destination in ['BOJ','LED'] or Segments[0].Origin in ['MOW','BHK'] and Segments[0].Destination in ['MOW','BHK'] or Segments[0].Origin in ['HKT','VVO'] and Segments[0].Destination in ['HKT','VVO'] or Segments[0].Origin in ['TOF','MOW'] and Segments[0].Destination in ['TOF','MOW'] or Segments[0].Origin in ['USM','KZN'] and Segments[0].Destination in ['USM','KZN'] or Segments[0].Origin in ['PUJ','KUF'] and Segments[0].Destination in ['PUJ','KUF'] or Segments[0].Origin in ['VOZ','PUJ'] and Segments[0].Destination in ['VOZ','PUJ'] or Segments[0].Origin in ['OVB','KRR'] and Segments[0].Destination in ['OVB','KRR'] or Segments[0].Origin in ['MOW','IKT'] and Segments[0].Destination in ['MOW','IKT'] or Segments[0].Origin in ['PEE','VRA'] and Segments[0].Destination in ['PEE','VRA'] or Segments[0].Origin in ['CFU','ROV'] and Segments[0].Destination in ['CFU','ROV'] or Segments[0].Origin in ['POP','MOW'] and Segments[0].Destination in ['POP','MOW'] or Segments[0].Origin in ['PUJ','SCW'] and Segments[0].Destination in ['PUJ','SCW'] or Segments[0].Origin in ['BAX','MOW'] and Segments[0].Destination in ['BAX','MOW'] or Segments[0].Origin in ['PUJ','SVX'] and Segments[0].Destination in ['PUJ','SVX'] or Segments[0].Origin in ['CUN','NJC'] and Segments[0].Destination in ['CUN','NJC'] or Segments[0].Origin in ['UTP','LED'] and Segments[0].Destination in ['UTP','LED'] or Segments[0].Origin in ['NHA','TJM'] and Segments[0].Destination in ['NHA','TJM'] or Segments[0].Origin in ['SGN','GOJ'] and Segments[0].Destination in ['SGN','GOJ'] or Segments[0].Origin in ['SSH','NBC'] and Segments[0].Destination in ['SSH','NBC'] or Segments[0].Origin in ['KJA','MOW'] and Segments[0].Destination in ['KJA','MOW'] or Segments[0].Origin in ['MOW','GPA'] and Segments[0].Destination in ['MOW','GPA'] or Segments[0].Origin in ['ATH','IEV'] and Segments[0].Destination in ['ATH','IEV'] or Segments[0].Origin in ['USM','VVO'] and Segments[0].Destination in ['USM','VVO'] or Segments[0].Origin in ['MOW','RMI'] and Segments[0].Destination in ['MOW','RMI'] or Segments[0].Origin in ['CEE','PUJ'] and Segments[0].Destination in ['CEE','PUJ'] or Segments[0].Origin in ['KRR','SKG'] and Segments[0].Destination in ['KRR','SKG'] or Segments[0].Origin in ['CUN','HTA'] and Segments[0].Destination in ['CUN','HTA'] or Segments[0].Origin in ['MRV','VRA'] and Segments[0].Destination in ['MRV','VRA'] or Segments[0].Origin in ['VRA','TJM'] and Segments[0].Destination in ['VRA','TJM'] or Segments[0].Origin in ['SKG','RIX'] and Segments[0].Destination in ['SKG','RIX'] or Segments[0].Origin in ['PRG','SVX'] and Segments[0].Destination in ['PRG','SVX'] or Segments[0].Origin in ['ABA','VRA'] and Segments[0].Destination in ['ABA','VRA'] or Segments[0].Origin in ['SGN','IKT'] and Segments[0].Destination in ['SGN','IKT'] or Segments[0].Origin in ['VOG','HRG'] and Segments[0].Destination in ['VOG','HRG'] or Segments[0].Origin in ['SVX','HER'] and Segments[0].Destination in ['SVX','HER'] or Segments[0].Origin in ['SHJ','VOG'] and Segments[0].Destination in ['SHJ','VOG'] or Segments[0].Origin in ['VRA','OGZ'] and Segments[0].Destination in ['VRA','OGZ'] or Segments[0].Origin in ['MOW','ZTH'] and Segments[0].Destination in ['MOW','ZTH'] or Segments[0].Origin in ['KJA','PUJ'] and Segments[0].Destination in ['KJA','PUJ'] or Segments[0].Origin in ['SSH','KJA'] and Segments[0].Destination in ['SSH','KJA'] or Segments[0].Origin in ['PUJ','NBC'] and Segments[0].Destination in ['PUJ','NBC'] or Segments[0].Origin in ['BKK','BAX'] and Segments[0].Destination in ['BKK','BAX'] or Segments[0].Origin in ['GOJ','HKT'] and Segments[0].Destination in ['GOJ','HKT'] or Segments[0].Origin in ['LED','AYT'] and Segments[0].Destination in ['LED','AYT'] or Segments[0].Origin in ['CEK','USM'] and Segments[0].Destination in ['CEK','USM'] or Segments[0].Origin in ['LED','SHJ'] and Segments[0].Destination in ['LED','SHJ'] or Segments[0].Origin in ['NOZ','BKK'] and Segments[0].Destination in ['NOZ','BKK'] or Segments[0].Origin in ['NOZ','PUJ'] and Segments[0].Destination in ['NOZ','PUJ'] or Segments[0].Origin in ['TJM','TDX'] and Segments[0].Destination in ['TJM','TDX'] or Segments[0].Origin in ['YKS','BKK'] and Segments[0].Destination in ['YKS','BKK'] or Segments[0].Origin in ['MOW','KUF'] and Segments[0].Destination in ['MOW','KUF'] or Segments[0].Origin in ['KJA','SGN'] and Segments[0].Destination in ['KJA','SGN'] or Segments[0].Origin in ['CEK','UTP'] and Segments[0].Destination in ['CEK','UTP'] or Segments[0].Origin in ['UFA','USM'] and Segments[0].Destination in ['UFA','USM'] or Segments[0].Origin in ['KZN','TDX'] and Segments[0].Destination in ['KZN','TDX'] or Segments[0].Origin in ['PEE','DXB'] and Segments[0].Destination in ['PEE','DXB'] or Segments[0].Origin in ['NJC','HKT'] and Segments[0].Destination in ['NJC','HKT'] or Segments[0].Origin in ['UFA','BKK'] and Segments[0].Destination in ['UFA','BKK'] or Segments[0].Origin in ['VOG','BKK'] and Segments[0].Destination in ['VOG','BKK'] or Segments[0].Origin in ['CEK','SGN'] and Segments[0].Destination in ['CEK','SGN'] or Segments[0].Origin in ['KZN','UTP'] and Segments[0].Destination in ['KZN','UTP'] or Segments[0].Origin in ['KJA','HKT'] and Segments[0].Destination in ['KJA','HKT'] or Segments[0].Origin in ['HTA','BKK'] and Segments[0].Destination in ['HTA','BKK'] or Segments[0].Origin in ['PEE','TDX'] and Segments[0].Destination in ['PEE','TDX'] or Segments[0].Origin in ['OVB','SGN'] and Segments[0].Destination in ['OVB','SGN'] or Segments[0].Origin in ['AER','HKT'] and Segments[0].Destination in ['AER','HKT'] or Segments[0].Origin in ['CUN','CEE'] and Segments[0].Destination in ['CUN','CEE'] or Segments[0].Origin in ['OGZ','MOW'] and Segments[0].Destination in ['OGZ','MOW'] or Segments[0].Origin in ['SVX','AQJ'] and Segments[0].Destination in ['SVX','AQJ'] or Segments[0].Origin in ['SVX','SHJ'] and Segments[0].Destination in ['SVX','SHJ'] or Segments[0].Origin in ['NHA','BTK'] and Segments[0].Destination in ['NHA','BTK'] or Segments[0].Origin in ['KZN','AQJ'] and Segments[0].Destination in ['KZN','AQJ'] or Segments[0].Origin in ['VOZ','DXB'] and Segments[0].Destination in ['VOZ','DXB'] or Segments[0].Origin in ['OGZ','HKT'] and Segments[0].Destination in ['OGZ','HKT'] or Segments[0].Origin in ['MOW','KLV'] and Segments[0].Destination in ['MOW','KLV'] or Segments[0].Origin in ['MOW','AQJ'] and Segments[0].Destination in ['MOW','AQJ'] or Segments[0].Origin in ['AER','SGN'] and Segments[0].Destination in ['AER','SGN'] or Segments[0].Origin in ['OVB','BKK'] and Segments[0].Destination in ['OVB','BKK'] or Segments[0].Origin in ['UFA','AYT'] and Segments[0].Destination in ['UFA','AYT'] or Segments[0].Origin in ['NOZ','SGN'] and Segments[0].Destination in ['NOZ','SGN'] or Segments[0].Origin in ['NBC','SGN'] and Segments[0].Destination in ['NBC','SGN'] or Segments[0].Origin in ['BQS','TDX'] and Segments[0].Destination in ['BQS','TDX'] or Segments[0].Origin in ['SGC','NHA'] and Segments[0].Destination in ['SGC','NHA'] or Segments[0].Origin in ['UFA','NHA'] and Segments[0].Destination in ['UFA','NHA'] or Segments[0].Origin in ['ROV','TDX'] and Segments[0].Destination in ['ROV','TDX'] or Segments[0].Origin in ['KZN','BKK'] and Segments[0].Destination in ['KZN','BKK'] or Segments[0].Origin in ['KJA','DXB'] and Segments[0].Destination in ['KJA','DXB'] or Segments[0].Origin in ['CEK','DXB'] and Segments[0].Destination in ['CEK','DXB'] or Segments[0].Origin in ['OVB','KBV'] and Segments[0].Destination in ['OVB','KBV'] or Segments[0].Origin in ['PEE','KBV'] and Segments[0].Destination in ['PEE','KBV'] or Segments[0].Origin in ['SVX','LED'] and Segments[0].Destination in ['SVX','LED'] or Segments[0].Origin in ['CUN','AAQ'] and Segments[0].Destination in ['CUN','AAQ'] or Segments[0].Origin in ['KEJ','BKK'] and Segments[0].Destination in ['KEJ','BKK'] or Segments[0].Origin in ['BQS','BKK'] and Segments[0].Destination in ['BQS','BKK'] or Segments[0].Origin in ['IKT','DXB'] and Segments[0].Destination in ['IKT','DXB'] or Segments[0].Origin in ['KUF','BKK'] and Segments[0].Destination in ['KUF','BKK'] or Segments[0].Origin in ['VVO','BKK'] and Segments[0].Destination in ['VVO','BKK'] or Segments[0].Origin in ['OVB','HKT'] and Segments[0].Destination in ['OVB','HKT'] or Segments[0].Origin in ['NHA','RTW'] and Segments[0].Destination in ['NHA','RTW'] or Segments[0].Origin in ['VOG','SGN'] and Segments[0].Destination in ['VOG','SGN'] or Segments[0].Origin in ['VVO','KBV'] and Segments[0].Destination in ['VVO','KBV'] or Segments[0].Origin in ['TOF','PUJ'] and Segments[0].Destination in ['TOF','PUJ'] or Segments[0].Origin in ['KEJ','HKT'] and Segments[0].Destination in ['KEJ','HKT'] or Segments[0].Origin in ['TJM','HKT'] and Segments[0].Destination in ['TJM','HKT'] or Segments[0].Origin in ['ROV','POP'] and Segments[0].Destination in ['ROV','POP'] or Segments[0].Origin in ['REN','ETH'] and Segments[0].Destination in ['REN','ETH'] or Segments[0].Origin in ['PEE','USM'] and Segments[0].Destination in ['PEE','USM'] or Segments[0].Origin in ['KEJ','SGN'] and Segments[0].Destination in ['KEJ','SGN'] or Segments[0].Origin in ['AER','DXB'] and Segments[0].Destination in ['AER','DXB'] or Segments[0].Origin in ['VOG','MOW'] and Segments[0].Destination in ['VOG','MOW'] or Segments[0].Origin in ['YKS','SGN'] and Segments[0].Destination in ['YKS','SGN'] or Segments[0].Origin in ['UFA','TDX'] and Segments[0].Destination in ['UFA','TDX'] or Segments[0].Origin in ['CUN','ABA'] and Segments[0].Destination in ['CUN','ABA'] or Segments[0].Origin in ['HRG','TJM'] and Segments[0].Destination in ['HRG','TJM'] or Segments[0].Origin in ['HTA','HKT'] and Segments[0].Destination in ['HTA','HKT'] or Segments[0].Origin in ['NBC','HKT'] and Segments[0].Destination in ['NBC','HKT'] or Segments[0].Origin in ['TOF','SGN'] and Segments[0].Destination in ['TOF','SGN'] or Segments[0].Origin in ['MCX','HKT'] and Segments[0].Destination in ['MCX','HKT'] or Segments[0].Origin in ['VRA','CEE'] and Segments[0].Destination in ['VRA','CEE'] or Segments[0].Origin in ['CUN','RTW'] and Segments[0].Destination in ['CUN','RTW'] or Segments[0].Origin in ['VOZ','SGN'] and Segments[0].Destination in ['VOZ','SGN'] or Segments[0].Origin in ['BQS','USM'] and Segments[0].Destination in ['BQS','USM'] or Segments[0].Origin in ['SGC','USM'] and Segments[0].Destination in ['SGC','USM'] or Segments[0].Origin in ['KZN','DXB'] and Segments[0].Destination in ['KZN','DXB'] or Segments[0].Origin in ['KEJ','TDX'] and Segments[0].Destination in ['KEJ','TDX'] or Segments[0].Origin in ['UFA','DXB'] and Segments[0].Destination in ['UFA','DXB'] or Segments[0].Origin in ['LED','HKT'] and Segments[0].Destination in ['LED','HKT'] or Segments[0].Origin in ['NJC','SGN'] and Segments[0].Destination in ['NJC','SGN'] or Segments[0].Origin in ['KUF','SHJ'] and Segments[0].Destination in ['KUF','SHJ'] or Segments[0].Origin in ['LED','AQJ'] and Segments[0].Destination in ['LED','AQJ'] or Segments[0].Origin in ['KJA','SIP'] and Segments[0].Destination in ['KJA','SIP'] or Segments[0].Origin in ['SGC','BKK'] and Segments[0].Destination in ['SGC','BKK'] or Segments[0].Origin in ['KJA','BKK'] and Segments[0].Destination in ['KJA','BKK'] or Segments[0].Origin in ['VOG','DXB'] and Segments[0].Destination in ['VOG','DXB'] or Segments[0].Origin in ['KEJ','USM'] and Segments[0].Destination in ['KEJ','USM'] or Segments[0].Origin in ['VVO','SGN'] and Segments[0].Destination in ['VVO','SGN'] or Segments[0].Origin in ['MOW','SIP'] and Segments[0].Destination in ['MOW','SIP'] or Segments[0].Origin in ['MOW','ROV'] and Segments[0].Destination in ['MOW','ROV'] or Segments[0].Origin in ['TJM','KBV'] and Segments[0].Destination in ['TJM','KBV'] or Segments[0].Origin in ['ROV','HKT'] and Segments[0].Destination in ['ROV','HKT'] or Segments[0].Origin in ['YKS','DXB'] and Segments[0].Destination in ['YKS','DXB'] or Segments[0].Origin in ['MOW','GDX'] and Segments[0].Destination in ['MOW','GDX'] or Segments[0].Origin in ['VOG','HKT'] and Segments[0].Destination in ['VOG','HKT'] or Segments[0].Origin in ['EGO','BKK'] and Segments[0].Destination in ['EGO','BKK'] or Segments[0].Origin in ['KGD','MOW'] and Segments[0].Destination in ['KGD','MOW'] or Segments[0].Origin in ['IKT','USM'] and Segments[0].Destination in ['IKT','USM'] or Segments[0].Origin in ['MOW','TDX'] and Segments[0].Destination in ['MOW','TDX'] or Segments[0].Origin in ['SVX','SGN'] and Segments[0].Destination in ['SVX','SGN'] or Segments[0].Origin in ['KRR','VRN'] and Segments[0].Destination in ['KRR','VRN'] or Segments[0].Origin in ['BAX','PUJ'] and Segments[0].Destination in ['BAX','PUJ'] or Segments[0].Origin in ['HRG','LED'] and Segments[0].Destination in ['HRG','LED'] or Segments[0].Origin in ['ASF','BKK'] and Segments[0].Destination in ['ASF','BKK'] or Segments[0].Origin in ['ROV','SHJ'] and Segments[0].Destination in ['ROV','SHJ'] or Segments[0].Origin in ['KRR','HKT'] and Segments[0].Destination in ['KRR','HKT'] or Segments[0].Origin in ['MOW','AYT'] and Segments[0].Destination in ['MOW','AYT'] or Segments[0].Origin in ['SVX','HKT'] and Segments[0].Destination in ['SVX','HKT'] or Segments[0].Origin in ['SVX','BKK'] and Segments[0].Destination in ['SVX','BKK'] or Segments[0].Origin in ['MOW','SGN'] and Segments[0].Destination in ['MOW','SGN'] or Segments[0].Origin in ['PEE','SSH'] and Segments[0].Destination in ['PEE','SSH'] or Segments[0].Origin in ['MOW','DXB'] and Segments[0].Destination in ['MOW','DXB'] or Segments[0].Origin in ['YKS','PUJ'] and Segments[0].Destination in ['YKS','PUJ'] or Segments[0].Origin in ['MOW','AUH'] and Segments[0].Destination in ['MOW','AUH'] or Segments[0].Origin in ['IKT','UTP'] and Segments[0].Destination in ['IKT','UTP'] or Segments[0].Origin in ['ROV','BKK'] and Segments[0].Destination in ['ROV','BKK'] or Segments[0].Origin in ['KGD','SGN'] and Segments[0].Destination in ['KGD','SGN'] or Segments[0].Origin in ['SCW','HKT'] and Segments[0].Destination in ['SCW','HKT'] or Segments[0].Origin in ['KGD','BKK'] and Segments[0].Destination in ['KGD','BKK'] or Segments[0].Origin in ['SGC','HKT'] and Segments[0].Destination in ['SGC','HKT'] or Segments[0].Origin in ['TSE','SKG'] and Segments[0].Destination in ['TSE','SKG'] or Segments[0].Origin in ['PKC','BKK'] and Segments[0].Destination in ['PKC','BKK'] or Segments[0].Origin in ['KEJ','KBV'] and Segments[0].Destination in ['KEJ','KBV'] or Segments[0].Origin in ['SCW','BKK'] and Segments[0].Destination in ['SCW','BKK'] or Segments[0].Origin in ['MOW','AMM'] and Segments[0].Destination in ['MOW','AMM'] or Segments[0].Origin in ['KZN','SGN'] and Segments[0].Destination in ['KZN','SGN'] or Segments[0].Origin in ['AER','VOG'] and Segments[0].Destination in ['AER','VOG'] or Segments[0].Origin in ['SVX','DXB'] and Segments[0].Destination in ['SVX','DXB'] or Segments[0].Origin in ['BQS','HKT'] and Segments[0].Destination in ['BQS','HKT'] or Segments[0].Origin in ['LED','DXB'] and Segments[0].Destination in ['LED','DXB'] or Segments[0].Origin in ['ROV','KBV'] and Segments[0].Destination in ['ROV','KBV'] or Segments[0].Origin in ['REN','BKK'] and Segments[0].Destination in ['REN','BKK'] or Segments[0].Origin in ['PEE','HKT'] and Segments[0].Destination in ['PEE','HKT'] or Segments[0].Origin in ['AER','BKK'] and Segments[0].Destination in ['AER','BKK'] or Segments[0].Origin in ['SCW','SGN'] and Segments[0].Destination in ['SCW','SGN'] or Segments[0].Origin in ['KUF','SIP'] and Segments[0].Destination in ['KUF','SIP'] or Segments[0].Origin in ['KRR','AQJ'] and Segments[0].Destination in ['KRR','AQJ'] or Segments[0].Origin in ['MOW','KBV'] and Segments[0].Destination in ['MOW','KBV'] or Segments[0].Origin in ['PEE','BKK'] and Segments[0].Destination in ['PEE','BKK'] or Segments[0].Origin in ['NBC','DXB'] and Segments[0].Destination in ['NBC','DXB'] or Segments[0].Origin in ['UUD','HKT'] and Segments[0].Destination in ['UUD','HKT'] or Segments[0].Origin in ['OVB','BTK'] and Segments[0].Destination in ['OVB','BTK'] or Segments[0].Origin in ['OVB','USM'] and Segments[0].Destination in ['OVB','USM'] or Segments[0].Origin in ['VRA','RTW'] and Segments[0].Destination in ['VRA','RTW'] or Segments[0].Origin in ['VOZ','SHJ'] and Segments[0].Destination in ['VOZ','SHJ'] or Segments[0].Origin in ['NOZ','DXB'] and Segments[0].Destination in ['NOZ','DXB'] or Segments[0].Origin in ['SGC','SGN'] and Segments[0].Destination in ['SGC','SGN'] or Segments[0].Origin in ['SVX','AYT'] and Segments[0].Destination in ['SVX','AYT'] or Segments[0].Origin in ['KZN','KBV'] and Segments[0].Destination in ['KZN','KBV'] or Segments[0].Origin in ['TJM','USM'] and Segments[0].Destination in ['TJM','USM'] or Segments[0].Origin in ['ROV','SGN'] and Segments[0].Destination in ['ROV','SGN'] or Segments[0].Origin in ['LED','AMM'] and Segments[0].Destination in ['LED','AMM'] or Segments[0].Origin in ['PUJ','RTW'] and Segments[0].Destination in ['PUJ','RTW'] or Segments[0].Origin in ['NJC','BKK'] and Segments[0].Destination in ['NJC','BKK'] or Segments[0].Origin in ['MOW','ROM'] and Segments[0].Destination in ['MOW','ROM'] or Segments[0].Origin in ['VOZ','BKK'] and Segments[0].Destination in ['VOZ','BKK'] or Segments[0].Origin in ['LED','KRR'] and Segments[0].Destination in ['LED','KRR'] or Segments[0].Origin in ['KUF','SGN'] and Segments[0].Destination in ['KUF','SGN'] or Segments[0].Origin in ['MRV','SGN'] and Segments[0].Destination in ['MRV','SGN'] or Segments[0].Origin in ['SSH','KGD'] and Segments[0].Destination in ['SSH','KGD'] or Segments[0].Origin in ['KRR','BKK'] and Segments[0].Destination in ['KRR','BKK'] or Segments[0].Origin in ['OVB','DXB'] and Segments[0].Destination in ['OVB','DXB'] or Segments[0].Origin in ['MRV','BKK'] and Segments[0].Destination in ['MRV','BKK'] or Segments[0].Origin in ['LED','BKK'] and Segments[0].Destination in ['LED','BKK'] or Segments[0].Origin in ['LED','SGN'] and Segments[0].Destination in ['LED','SGN'] or Segments[0].Origin in ['REN','HKT'] and Segments[0].Destination in ['REN','HKT'] or Segments[0].Origin in ['UUD','BKK'] and Segments[0].Destination in ['UUD','BKK'] or Segments[0].Origin in ['GOJ','PUJ'] and Segments[0].Destination in ['GOJ','PUJ'] or Segments[0].Origin in ['BAX','TDX'] and Segments[0].Destination in ['BAX','TDX'] or Segments[0].Origin in ['KJA','UTP'] and Segments[0].Destination in ['KJA','UTP'] or Segments[0].Origin in ['KHV','BKK'] and Segments[0].Destination in ['KHV','BKK'] or Segments[0].Origin in ['MOW','BER'] and Segments[0].Destination in ['MOW','BER'] or Segments[0].Origin in ['KHV','SGN'] and Segments[0].Destination in ['KHV','SGN'] or Segments[0].Origin in ['NJC','DXB'] and Segments[0].Destination in ['NJC','DXB'] or Segments[0].Origin in ['BAX','USM'] and Segments[0].Destination in ['BAX','USM'] or Segments[0].Origin in ['VRN','ROV'] and Segments[0].Destination in ['VRN','ROV'] or Segments[0].Origin in ['IKT','BKK'] and Segments[0].Destination in ['IKT','BKK'] or Segments[0].Origin in ['SGC','TDX'] and Segments[0].Destination in ['SGC','TDX'] or Segments[0].Origin in ['TOF','BKK'] and Segments[0].Destination in ['TOF','BKK'] or Segments[0].Origin in ['SVX','SIP'] and Segments[0].Destination in ['SVX','SIP'] or Segments[0].Origin in ['HRG','PEE'] and Segments[0].Destination in ['HRG','PEE'] or Segments[0].Origin in ['MOW','GVA'] and Segments[0].Destination in ['MOW','GVA'] or Segments[0].Origin in ['MOW','MUC'] and Segments[0].Destination in ['MOW','MUC'] or Segments[0].Origin in ['BAX','HKT'] and Segments[0].Destination in ['BAX','HKT'] or Segments[0].Origin in ['HTA','SGN'] and Segments[0].Destination in ['HTA','SGN'] or Segments[0].Origin in ['MOW','SHJ'] and Segments[0].Destination in ['MOW','SHJ'] or Segments[0].Origin in ['UFA','KBV'] and Segments[0].Destination in ['UFA','KBV'] or Segments[0].Origin in ['MOW','DJE'] and Segments[0].Destination in ['MOW','DJE'] or Segments[0].Origin in ['PEE','SGN'] and Segments[0].Destination in ['PEE','SGN'] or Segments[0].Origin in ['LED','CUN'] and Segments[0].Destination in ['LED','CUN'] or Segments[0].Origin in ['SVX','MOW'] and Segments[0].Destination in ['SVX','MOW'] or Segments[0].Origin in ['SGC','KBV'] and Segments[0].Destination in ['SGC','KBV'] or Segments[0].Origin in ['GOJ','DXB'] and Segments[0].Destination in ['GOJ','DXB'] or Segments[0].Origin in ['BAX','SGN'] and Segments[0].Destination in ['BAX','SGN'] or Segments[0].Origin in ['HRG','ROV'] and Segments[0].Destination in ['HRG','ROV'] or Segments[0].Origin in ['IKT','TDX'] and Segments[0].Destination in ['IKT','TDX'] or Segments[0].Origin in ['UFA','SGN'] and Segments[0].Destination in ['UFA','SGN'] or Segments[0].Origin in ['KHV','HKT'] and Segments[0].Destination in ['KHV','HKT'] or Segments[0].Origin in ['KRR','SIP'] and Segments[0].Destination in ['KRR','SIP'] or Segments[0].Origin in ['VRA','AAQ'] and Segments[0].Destination in ['VRA','AAQ'] or Segments[0].Origin in ['BQS','KBV'] and Segments[0].Destination in ['BQS','KBV'] or Segments[0].Origin in ['NBC','BKK'] and Segments[0].Destination in ['NBC','BKK'] or Segments[0].Origin in ['NOZ','HKT'] and Segments[0].Destination in ['NOZ','HKT'] or Segments[0].Origin in ['LED','SIP'] and Segments[0].Destination in ['LED','SIP'] or Segments[0].Origin in ['BGY','MOW'] and Segments[0].Destination in ['BGY','MOW'] or Segments[0].Origin in ['EGO','HKT'] and Segments[0].Destination in ['EGO','HKT'] or Segments[0].Origin in ['OVB','NHA'] and Segments[0].Destination in ['OVB','NHA'] or Segments[0].Origin in ['TJM','BKK'] and Segments[0].Destination in ['TJM','BKK'] or Segments[0].Origin in ['BAX','DXB'] and Segments[0].Destination in ['BAX','DXB'] or Segments[0].Origin in ['CEK','HKT'] and Segments[0].Destination in ['CEK','HKT'] or Segments[0].Origin in ['KGD','HKT'] and Segments[0].Destination in ['KGD','HKT'] or Segments[0].Origin in ['SVX','USM'] and Segments[0].Destination in ['SVX','USM'] or Segments[0].Origin in ['BAX','KBV'] and Segments[0].Destination in ['BAX','KBV'] or Segments[0].Origin in ['UFA','SIP'] and Segments[0].Destination in ['UFA','SIP'] or Segments[0].Origin in ['LED','NHA'] and Segments[0].Destination in ['LED','NHA'] or Segments[0].Origin in ['VOZ','HKT'] and Segments[0].Destination in ['VOZ','HKT'] or Segments[0].Origin in ['GOJ','BKK'] and Segments[0].Destination in ['GOJ','BKK'] or Segments[0].Origin in ['ASF','HKT'] and Segments[0].Destination in ['ASF','HKT'] or Segments[0].Origin in ['AER','SIP'] and Segments[0].Destination in ['AER','SIP'] or Segments[0].Origin in ['TJM','SGN'] and Segments[0].Destination in ['TJM','SGN'] or Segments[0].Origin in ['MOW','MIL'] and Segments[0].Destination in ['MOW','MIL'] or Segments[0].Origin in ['MOW','USM'] and Segments[0].Destination in ['MOW','USM'] or Segments[0].Origin in ['IKT','KBV'] and Segments[0].Destination in ['IKT','KBV'] or Segments[0].Origin in ['UFA','HKT'] and Segments[0].Destination in ['UFA','HKT'] or Segments[0].Origin in ['EGO','UTP'] and Segments[0].Destination in ['EGO','UTP'] or Segments[0].Origin in ['HTA','DXB'] and Segments[0].Destination in ['HTA','DXB'] or Segments[0].Origin in ['OMS','SGN'] and Segments[0].Destination in ['OMS','SGN'] or Segments[0].Origin in ['PUJ','HTA'] and Segments[0].Destination in ['PUJ','HTA'] or Segments[0].Origin in ['OMS','HKT'] and Segments[0].Destination in ['OMS','HKT'] or Segments[0].Origin in ['KUF','DXB'] and Segments[0].Destination in ['KUF','DXB'] or Segments[0].Origin in ['MCX','BKK'] and Segments[0].Destination in ['MCX','BKK'] or Segments[0].Origin in ['IKT','HKT'] and Segments[0].Destination in ['IKT','HKT'] or Segments[0].Origin in ['ROV','DXB'] and Segments[0].Destination in ['ROV','DXB'] or Segments[0].Origin in ['TJM','DXB'] and Segments[0].Destination in ['TJM','DXB'] or Segments[0].Origin in ['OMS','USM'] and Segments[0].Destination in ['OMS','USM'] or Segments[0].Origin in ['KRR','DXB'] and Segments[0].Destination in ['KRR','DXB'] or Segments[0].Origin in ['KZN','HKT'] and Segments[0].Destination in ['KZN','HKT'] or Segments[0].Origin in ['LED','USM'] and Segments[0].Destination in ['LED','USM'] or Segments[0].Origin in ['MRV','HKT'] and Segments[0].Destination in ['MRV','HKT'] or Segments[0].Origin in ['TOF','HKT'] and Segments[0].Destination in ['TOF','HKT'] or Segments[0].Origin in ['KEJ','DXB'] and Segments[0].Destination in ['KEJ','DXB'] or Segments[0].Origin in ['MRV','DXB'] and Segments[0].Destination in ['MRV','DXB'] or Segments[0].Origin in ['OGZ','BKK'] and Segments[0].Destination in ['OGZ','BKK'] or Segments[0].Origin in ['PEE','UTP'] and Segments[0].Destination in ['PEE','UTP'] or Segments[0].Origin in ['ROV','USM'] and Segments[0].Destination in ['ROV','USM'] or Segments[0].Origin in ['KUF','UTP'] and Segments[0].Destination in ['KUF','UTP'] or Segments[0].Origin in ['KZN','SIP'] and Segments[0].Destination in ['KZN','SIP'] or Segments[0].Origin in ['REN','SHJ'] and Segments[0].Destination in ['REN','SHJ'] or Segments[0].Origin in ['KRR','SGN'] and Segments[0].Destination in ['KRR','SGN'] or Segments[0].Origin in ['MOW','BUH'] and Segments[0].Destination in ['MOW','BUH'] or Segments[0].Origin in ['BQS','SGN'] and Segments[0].Destination in ['BQS','SGN'] or Segments[0].Origin in ['TOF','DXB'] and Segments[0].Destination in ['TOF','DXB'] or Segments[0].Origin in ['KUF','HKT'] and Segments[0].Destination in ['KUF','HKT'] or Segments[0].Origin in ['HRG','SCW'] and Segments[0].Destination in ['HRG','SCW'] or Segments[0].Origin in ['PEE','AYT'] and Segments[0].Destination in ['PEE','AYT'] or Segments[0].Origin in ['OMS','BKK'] and Segments[0].Destination in ['OMS','BKK'] or Segments[0].Origin in ['CEK','BKK'] and Segments[0].Destination in ['CEK','BKK'] or Segments[0].Origin in ['YKS','HKT'] and Segments[0].Destination in ['YKS','HKT'] or Segments[0].Origin in ['MOW','TRN'] and Segments[0].Destination in ['MOW','TRN'] or Segments[0].Origin in ['OMS','DXB'] and Segments[0].Destination in ['OMS','DXB'] or Segments[0].Origin in ['VVO','HKT'] and Segments[0].Destination in ['VVO','HKT'] or Segments[0].Origin in ['KZN','USM'] and Segments[0].Destination in ['KZN','USM'] or Segments[0].Origin in ['MOW','POP'] and Segments[0].Destination in ['MOW','POP'] or Segments[0].Origin in ['LED','UTP'] and Segments[0].Destination in ['LED','UTP'] or Segments[0].Origin in ['GOJ','SGN'] and Segments[0].Destination in ['GOJ','SGN'] or Segments[0].Origin in ['VVO','USM'] and Segments[0].Destination in ['VVO','USM'] or Segments[0].Origin in ['PUJ','CEE'] and Segments[0].Destination in ['PUJ','CEE'] or Segments[0].Origin in ['SVX','PRG'] and Segments[0].Destination in ['SVX','PRG'] or Segments[0].Origin in ['VRA','ABA'] and Segments[0].Destination in ['VRA','ABA'] or Segments[0].Origin in ['IKT','SGN'] and Segments[0].Destination in ['IKT','SGN'] or Segments[0].Origin in ['VOG','SHJ'] and Segments[0].Destination in ['VOG','SHJ'])` + program, err := expr.Compile(expression, expr.Env(env)) if err != nil { b.Fatal(err) } - var out interface{} - for n := 0; n < b.N; n++ { - out, err = vm.Run(program, env) - } + b.Run("no_common_reused", func(b *testing.B) { + for i := 0; i < b.N; i++ { + var out interface{} + out, err = vm.Run(program, env) + if err != nil { + b.Fatal(err) + } + if !out.(bool) { + b.Fail() + } + } + }) + + program, err = expr.Compile(expression, expr.Env(env), expr.AllowReuseCommon(true)) if err != nil { b.Fatal(err) } - if !out.(bool) { - b.Fail() - } + + b.Run("allow_common_reused", func(b *testing.B) { + for i := 0; i < b.N; i++ { + var out interface{} + out, err = vm.Run(program, env) + if err != nil { + b.Fatal(err) + } + if !out.(bool) { + b.Fail() + } + } + }) } diff --git a/compiler/check_common.go b/compiler/check_common.go new file mode 100644 index 000000000..7f3e16ac0 --- /dev/null +++ b/compiler/check_common.go @@ -0,0 +1,368 @@ +package compiler + +import ( + "crypto/sha1" + "fmt" + "sort" + "strconv" + "strings" + + "github.com/antonmedv/expr/ast" + "github.com/antonmedv/expr/file" +) + +func (c *compiler) countCommonExpr(node ast.Node) { + switch n := node.(type) { + case *ast.NilNode: + c.commonCommonNilNode(n) + case *ast.IdentifierNode: + c.countCommonIdentifierNode(n) + case *ast.IntegerNode: + c.countCommonIntegerNode(n) + case *ast.FloatNode: + c.countCommonFloatNode(n) + case *ast.BoolNode: + c.countCommonBoolNode(n) + case *ast.StringNode: + c.countCommonStringNode(n) + case *ast.ConstantNode: + c.countCommonConstantNode(n) + case *ast.UnaryNode: + c.countCommonUnaryNode(n) + case *ast.BinaryNode: + c.countCommonBinaryNode(n) + case *ast.ChainNode: + c.countCommonChainNode(n) + case *ast.MemberNode: + c.countCommonMemberNode(n) + case *ast.SliceNode: + c.countCommonSliceNode(n) + case *ast.CallNode: + c.checkCallNode(n) + case *ast.BuiltinNode: + c.countCommonBuiltinNode(n) + case *ast.ClosureNode: + c.countCommonClosureNode(n) + case *ast.PointerNode: + c.countCommonPointerNode(n) + case *ast.ConditionalNode: + c.countCommonConditionalNode(n) + case *ast.ArrayNode: + c.countCommonArrayNode(n) + case *ast.MapNode: + c.countCommonMapNode(n) + case *ast.PairNode: + // do nothing + default: + panic(fmt.Sprintf("undefined node type (%T)", node)) + } +} + +func (c *compiler) commonCommonNilNode(n *ast.NilNode) { + n.SetSubExpr("nil") +} + +func (c *compiler) countCommonIdentifierNode(n *ast.IdentifierNode) { + n.SetSubExpr(n.Value) +} + +func (c *compiler) countCommonIntegerNode(n *ast.IntegerNode) { + n.SetSubExpr(strconv.FormatInt(int64(n.Value), 10)) +} + +func (c *compiler) countCommonFloatNode(n *ast.FloatNode) { + n.SetSubExpr(strconv.FormatFloat(n.Value, 'f', 10, 64)) +} + +func (c *compiler) countCommonBoolNode(n *ast.BoolNode) { + n.SetSubExpr(strconv.FormatBool(n.Value)) +} + +func (c *compiler) countCommonStringNode(n *ast.StringNode) { + n.SetSubExpr(strconv.Quote(n.Value)) +} + +func (c *compiler) countCommonConstantNode(n *ast.ConstantNode) { + var s string + switch n.Value.(type) { + case string: + s = strconv.Quote(n.Value.(string)) + case int: + s = strconv.FormatInt(int64(n.Value.(int)), 10) + case int8: + s = strconv.FormatInt(int64(n.Value.(int8)), 10) + case int16: + s = strconv.FormatInt(int64(n.Value.(int16)), 10) + case int32: + s = strconv.FormatInt(int64(n.Value.(int32)), 10) + case int64: + s = strconv.FormatInt(n.Value.(int64), 10) + case uint: + s = strconv.FormatUint(uint64(n.Value.(uint)), 10) + case uint8: + s = strconv.FormatUint(uint64(n.Value.(uint8)), 10) + case uint16: + s = strconv.FormatUint(uint64(n.Value.(uint16)), 10) + case uint32: + s = strconv.FormatUint(uint64(n.Value.(uint32)), 10) + case uint64: + s = strconv.FormatUint(uint64(n.Value.(uint64)), 10) + case float32: + s = strconv.FormatFloat(float64(n.Value.(float32)), 'f', 10, 32) + case float64: + s = strconv.FormatFloat(n.Value.(float64), 'f', 10, 64) + default: + s = fmt.Sprintf("%+v", n.Value) + } + n.SetSubExpr(s) +} + +func (c *compiler) countCommonUnaryNode(n *ast.UnaryNode) { + c.countCommonExpr(n.Node) + buf := strings.Builder{} + switch n.Operator { + case "+": + buf.WriteString("") + case "-": + buf.WriteString("-(") + case "not", "!": + buf.WriteString("not (") + } + buf.WriteString(n.Node.SubExpr()) + buf.WriteString(")") + n.SetSubExpr(buf.String()) +} + +func (c *compiler) countCommonBinaryNode(n *ast.BinaryNode) { + c.countCommonExpr(n.Left) + c.countCommonExpr(n.Right) + + ls := n.Left.SubExpr() + rs := n.Right.SubExpr() + _, lw := n.Left.(*ast.BinaryNode) + _, rw := n.Right.(*ast.BinaryNode) + op := n.Operator + switch op { + case "==", "!=", "and", "or", "+", "*", "||", "&&", ">=", "<=": // right / left can be swap + if op == ">=" || op == "<=" || rs <= ls { + ls, rs = rs, ls + lw, rw = rw, lw + } + if op == "&&" { + op = "and" + } else if op == "||" { + op = "or" + } else if op == ">=" { + op = "<" + } else if op == "<=" { + op = ">" + } + case "**", "^": + op = "**" + default: + // do nothing + } + + buf := strings.Builder{} + if lw { + buf.WriteString("(") + buf.WriteString(ls) + buf.WriteString(")") + } else { + buf.WriteString(ls) + } + buf.WriteString(" " + op + " ") + if rw { + buf.WriteString("(") + buf.WriteString(rs) + buf.WriteString(")") + } else { + buf.WriteString(rs) + } + n.SetSubExpr(buf.String()) + + switch n.Operator { + case "??", "and", "or", "||", "&&": + // do nothing + default: + c.emitSubExpr(n.SubExpr(), n.Location()) + } +} + +func (c *compiler) countCommonChainNode(n *ast.ChainNode) { + c.countCommonExpr(n.Node) + n.SetSubExpr(n.Node.SubExpr()) +} + +func (c *compiler) countCommonMemberNode(n *ast.MemberNode) { + c.countCommonExpr(n.Node) + buf := strings.Builder{} + buf.WriteString(n.Node.SubExpr()) + if n.Method { + buf.WriteString(".") + buf.WriteString(n.Name) + } else { + if len(n.FieldIndex) > 0 { + if n.Optional { + buf.WriteString("?") + } + buf.WriteString(".") + buf.WriteString(n.Name) + } else { + c.countCommonExpr(n.Property) + buf.WriteString("[") + buf.WriteString(n.Property.SubExpr()) + buf.WriteString("]") + } + } + n.SetSubExpr(buf.String()) +} + +func (c *compiler) countCommonSliceNode(n *ast.SliceNode) { + buf := strings.Builder{} + c.countCommonExpr(n.Node) + buf.WriteString(n.Node.SubExpr()) + buf.WriteString("[") + toStr := "" + fromStr := "" + if n.To != nil { + c.countCommonExpr(n.To) + toStr = n.To.SubExpr() + } + if n.From != nil { + c.countCommonExpr(n.From) + fromStr = n.From.SubExpr() + } + buf.WriteString(fromStr) + buf.WriteString(":") + buf.WriteString(toStr) + buf.WriteString("]") + n.SetSubExpr(buf.String()) +} + +func (c *compiler) checkCallNode(n *ast.CallNode) { + argStr := strings.Builder{} + for i, arg := range n.Arguments { + c.countCommonExpr(arg) + if i != 0 { + argStr.WriteString(",") + } + argStr.WriteString(arg.SubExpr()) + } + c.countCommonExpr(n.Callee) + + buf := strings.Builder{} + buf.WriteString(n.Callee.SubExpr()) + buf.WriteString("(") + buf.WriteString(argStr.String()) + buf.WriteString(")") + n.SetSubExpr(buf.String()) +} + +func (c *compiler) countCommonBuiltinNode(n *ast.BuiltinNode) { + buf := strings.Builder{} + buf.WriteString(n.Name) + buf.WriteString("(") + for i, arg := range n.Arguments { + c.countCommonExpr(arg) + if i != 0 { + buf.WriteString(",") + } + buf.WriteString(arg.SubExpr()) + } + buf.WriteString(")") + n.SetSubExpr(buf.String()) +} + +func (c *compiler) countCommonClosureNode(n *ast.ClosureNode) { + c.countCommonExpr(n.Node) + // omit '{' / '}' + n.SetSubExpr(n.Node.SubExpr()) +} + +func (c *compiler) countCommonPointerNode(n *ast.PointerNode) { + // do nothing + n.SetSubExpr("#") +} + +func (c *compiler) countCommonConditionalNode(n *ast.ConditionalNode) { + c.countCommonExpr(n.Cond) + c.countCommonExpr(n.Exp1) + c.countCommonExpr(n.Exp2) + buf := strings.Builder{} + buf.WriteString(n.Cond.SubExpr()) + buf.WriteString(" ? ") + buf.WriteString(n.Exp1.SubExpr()) + buf.WriteString(" : ") + buf.WriteString(n.Exp2.SubExpr()) + n.SetSubExpr(buf.String()) +} + +func (c *compiler) countCommonArrayNode(n *ast.ArrayNode) { + buf := strings.Builder{} + buf.WriteString("[") + for i, node := range n.Nodes { + c.countCommonExpr(node) + if i != 0 { + buf.WriteString(",") + } + buf.WriteString(node.SubExpr()) + } + buf.WriteString("]") + n.SetSubExpr(buf.String()) +} + +func (c *compiler) countCommonMapNode(n *ast.MapNode) { + pairs := make([]*ast.PairNode, 0) + for i := range n.Pairs { + pair := n.Pairs[i].(*ast.PairNode) + c.countCommonExpr(pair.Key) + c.countCommonExpr(pair.Value) + pairs = append(pairs, pair) + } + sort.Slice(pairs, func(i, j int) bool { + return pairs[i].Key.SubExpr() < pairs[j].Key.SubExpr() + }) + buf := strings.Builder{} + buf.WriteString("{") + for i, pair := range pairs { + if i != 0 { + buf.WriteString(",") + } + buf.WriteString(pair.Key.SubExpr()) + buf.WriteString(":") + buf.WriteString(pair.Value.SubExpr()) + } + buf.WriteString("}") + n.SetSubExpr(buf.String()) +} + +func (c *compiler) emitSubExpr(subExpr string, loc file.Location) { + if c.exprRecords == nil || subExpr == "" { + return + } + hash := fmt.Sprintf("%x", sha1.Sum([]byte(subExpr))) + if cs, ok := c.exprRecords[hash]; !ok { + c.exprRecords[hash] = &exprRecord{cnt: 1} + } else { + if cs.cnt == 1 { + cs.id = c.commonExprInc + c.commonExpr[cs.id] = subExpr + c.commonExprInc += 1 + } + cs.cnt = cs.cnt + 1 + } +} + +func (c *compiler) needCacheCommon(n ast.Node) (bool, int) { + needCacheCommon, exprUniqId := false, -1 + if c.exprRecords != nil { + hash := fmt.Sprintf("%x", sha1.Sum([]byte(n.SubExpr()))) + cs, ok := c.exprRecords[hash] + if ok && cs.cnt > 1 { + needCacheCommon = true + exprUniqId = cs.id + } + } + return needCacheCommon, exprUniqId +} diff --git a/compiler/compiler.go b/compiler/compiler.go index 3cd32af0f..7b7f5fff7 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -32,6 +32,16 @@ func Compile(tree *parser.Tree, config *conf.Config) (program *Program, err erro if config != nil { c.mapEnv = config.MapEnv c.cast = config.Expect + if config.AllowReuseCommon { + c.commonExprInc = 0 + c.commonExpr = make(map[int]string) + c.exprRecords = make(map[string]*exprRecord) + c.countCommonExpr(tree.Node) + defer func() { + program.CommonExpr = c.commonExpr + program.CommonCache = make([]interface{}, len(c.commonExpr)) + }() + } } c.compile(tree.Node) @@ -69,6 +79,15 @@ type compiler struct { nodes []ast.Node chains [][]int arguments []int + + commonExpr map[int]string // exprUniqId => expr string + exprRecords map[string]*exprRecord // record sub expr cache count, hash(expr string) => exprRecord + commonExprInc int // common expr increment number id, increment exprUniqId +} + +type exprRecord struct { + id int // sub-expr uniq id + cnt int // how many times of sub-expr repeated } func (c *compiler) emitLocation(loc file.Location, op Opcode, arg int) int { @@ -285,7 +304,6 @@ func (c *compiler) ConstantNode(node *ast.ConstantNode) { func (c *compiler) UnaryNode(node *ast.UnaryNode) { c.compile(node.Node) - switch node.Operator { case "!", "not": @@ -303,9 +321,18 @@ func (c *compiler) UnaryNode(node *ast.UnaryNode) { } func (c *compiler) BinaryNode(node *ast.BinaryNode) { + if needCacheResult, exprUniqId := c.needCacheCommon(node); needCacheResult { + c.emit(OpLoadCommon, exprUniqId) + cEnd := c.emit(OpJumpIfSaveCommon, placeholder) + c.emit(OpPop) + defer func() { + c.emit(OpSaveCommon, exprUniqId) + c.patchJump(cEnd) + }() + } + l := kind(node.Left) r := kind(node.Right) - switch node.Operator { case "==": c.compile(node.Left) @@ -322,7 +349,13 @@ func (c *compiler) BinaryNode(node *ast.BinaryNode) { case "!=": c.compile(node.Left) c.compile(node.Right) - c.emit(OpEqual) + if l == r && l == reflect.Int { + c.emit(OpEqualInt) + } else if l == r && l == reflect.String { + c.emit(OpEqualString) + } else { + c.emit(OpEqual) + } c.emit(OpNot) case "or", "||": @@ -530,6 +563,16 @@ func (c *compiler) SliceNode(node *ast.SliceNode) { } func (c *compiler) CallNode(node *ast.CallNode) { + if needCacheResult, exprUniqId := c.needCacheCommon(node); needCacheResult { + c.emit(OpLoadCommon, exprUniqId) + cEnd := c.emit(OpJumpIfSaveCommon, placeholder) + c.emit(OpPop) + defer func() { + c.emit(OpSaveCommon, exprUniqId) + c.patchJump(cEnd) + }() + } + for _, arg := range node.Arguments { c.compile(arg) } diff --git a/conf/config.go b/conf/config.go index 1ac0fa7d2..f50fb1db5 100644 --- a/conf/config.go +++ b/conf/config.go @@ -21,6 +21,8 @@ type Config struct { ConstFns map[string]reflect.Value Visitors []ast.Visitor Functions map[string]*builtin.Function + + AllowReuseCommon bool // allow cache common sub-expr computed result, aimed to reuse already computed result } // CreateNew creates new config with default values. diff --git a/expr.go b/expr.go index 6aa674fb5..17ef9a4c3 100644 --- a/expr.go +++ b/expr.go @@ -123,6 +123,13 @@ func Function(name string, fn func(params ...interface{}) (interface{}, error), } } +// AllowCacheCommon allow cache common sub-expr computed result, aimed to reuse already computed result +func AllowReuseCommon(allow bool) Option { + return func(c *conf.Config) { + c.AllowReuseCommon = allow + } +} + // Compile parses and compiles given input expression to bytecode program. func Compile(input string, ops ...Option) (*vm.Program, error) { config := conf.CreateNew() diff --git a/vm/opcodes.go b/vm/opcodes.go index b3117e73c..fadd1d85c 100644 --- a/vm/opcodes.go +++ b/vm/opcodes.go @@ -27,6 +27,7 @@ const ( OpJumpIfFalse OpJumpIfNil OpJumpIfNotNil + OpJumpIfSaveCommon // if common value save skip common calculate OpJumpIfEnd OpJumpBackward OpIn @@ -66,6 +67,8 @@ const ( OpGetCount OpGetLen OpPointer + OpSaveCommon // save common sub-expr value + OpLoadCommon // load common sub-expr value OpBegin OpEnd // This opcode must be at the end of this list. ) diff --git a/vm/program.go b/vm/program.go index d424df14f..6eaf22dfd 100644 --- a/vm/program.go +++ b/vm/program.go @@ -15,13 +15,15 @@ import ( ) type Program struct { - Node ast.Node - Source *file.Source - Locations []file.Location - Constants []interface{} - Bytecode []Opcode - Arguments []int - Functions []Function + Node ast.Node + Source *file.Source + Locations []file.Location + Constants []interface{} + Bytecode []Opcode + Arguments []int + Functions []Function + CommonExpr map[int]string + CommonCache []interface{} } func (program *Program) Disassemble() string { @@ -46,6 +48,9 @@ func (program *Program) Disassemble() string { argument := func(label string) { _, _ = fmt.Fprintf(w, "%v\t%v\t<%v>\n", pp, label, arg) } + commonExpr := func(label string) { + _, _ = fmt.Fprintf(w, "%v\t%v\t<%v>\t(%s)\n", pp, label, arg, program.CommonExpr[arg]) + } constant := func(label string) { var c interface{} if arg < len(program.Constants) { @@ -145,6 +150,9 @@ func (program *Program) Disassemble() string { case OpJumpIfNotNil: jump("OpJumpIfNotNil") + case OpJumpIfSaveCommon: + jump("OpJumpIfSaveCommon") + case OpJumpIfEnd: jump("OpJumpIfEnd") @@ -263,6 +271,12 @@ func (program *Program) Disassemble() string { case OpPointer: code("OpPointer") + case OpSaveCommon: + commonExpr("OpSaveCommon") + + case OpLoadCommon: + commonExpr("OpLoadCommon") + case OpBegin: code("OpBegin") diff --git a/vm/vm.go b/vm/vm.go index af4fc5bf7..9a9714313 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -16,6 +16,11 @@ import ( var MemoryBudget int = 1e6 var errorType = reflect.TypeOf((*error)(nil)).Elem() +// just for expr not save common result +type notSave struct{} + +var _notSave = ¬Save{} + type Function = func(params ...interface{}) (interface{}, error) func Run(program *Program, env interface{}) (interface{}, error) { @@ -48,8 +53,8 @@ type Scope struct { func Debug() *VM { vm := &VM{ debug: true, - step: make(chan struct{}, 0), - curr: make(chan int, 0), + step: make(chan struct{}), + curr: make(chan int), } return vm } @@ -67,17 +72,20 @@ func (vm *VM) Run(program *Program, env interface{}) (_ interface{}, err error) err = f.Bind(program.Source) } }() - if vm.stack == nil { - vm.stack = make([]interface{}, 0, 2) + vm.stack = make([]interface{}, 0, 64) } else { vm.stack = vm.stack[0:0] } - - if vm.scopes != nil { + if vm.scopes == nil { + vm.scopes = make([]*Scope, 0, 64) + } else { vm.scopes = vm.scopes[0:0] } + for i := 0; i < len(program.CommonCache); i++ { + program.CommonCache[i] = _notSave + } vm.memoryBudget = MemoryBudget vm.memory = 0 vm.ip = 0 @@ -90,9 +98,7 @@ func (vm *VM) Run(program *Program, env interface{}) (_ interface{}, err error) op := program.Bytecode[vm.ip] arg := program.Arguments[vm.ip] vm.ip += 1 - switch op { - case OpPush: vm.push(program.Constants[arg]) @@ -182,6 +188,11 @@ func (vm *VM) Run(program *Program, env interface{}) (_ interface{}, err error) vm.ip += arg } + case OpJumpIfSaveCommon: + if _, ok := vm.current().(*notSave); !ok { + vm.ip += arg + } + case OpJumpIfEnd: scope := vm.Scope() if scope.It >= scope.Len { @@ -439,6 +450,12 @@ func (vm *VM) Run(program *Program, env interface{}) (_ interface{}, err error) scope := vm.Scope() vm.push(scope.Array.Index(scope.It).Interface()) + case OpSaveCommon: + program.CommonCache[arg] = vm.current() + + case OpLoadCommon: + vm.push(program.CommonCache[arg]) + case OpBegin: a := vm.pop() array := reflect.ValueOf(a) From c08954caf500fe8db880de74275063ad4b98f078 Mon Sep 17 00:00:00 2001 From: zhuliquan Date: Mon, 24 Jul 2023 01:33:16 +0800 Subject: [PATCH 03/11] feature: inc expr uniq id according to order of compiler --- compiler/check_common.go | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/compiler/check_common.go b/compiler/check_common.go index 7f3e16ac0..6b859c6d1 100644 --- a/compiler/check_common.go +++ b/compiler/check_common.go @@ -241,20 +241,17 @@ func (c *compiler) countCommonSliceNode(n *ast.SliceNode) { } func (c *compiler) checkCallNode(n *ast.CallNode) { - argStr := strings.Builder{} + buf := strings.Builder{} + c.countCommonExpr(n.Callee) + buf.WriteString(n.Callee.SubExpr()) + buf.WriteString("(") for i, arg := range n.Arguments { c.countCommonExpr(arg) if i != 0 { - argStr.WriteString(",") + buf.WriteString(",") } - argStr.WriteString(arg.SubExpr()) + buf.WriteString(arg.SubExpr()) } - c.countCommonExpr(n.Callee) - - buf := strings.Builder{} - buf.WriteString(n.Callee.SubExpr()) - buf.WriteString("(") - buf.WriteString(argStr.String()) buf.WriteString(")") n.SetSubExpr(buf.String()) } @@ -343,13 +340,8 @@ func (c *compiler) emitSubExpr(subExpr string, loc file.Location) { } hash := fmt.Sprintf("%x", sha1.Sum([]byte(subExpr))) if cs, ok := c.exprRecords[hash]; !ok { - c.exprRecords[hash] = &exprRecord{cnt: 1} + c.exprRecords[hash] = &exprRecord{cnt: 1, id: -1} } else { - if cs.cnt == 1 { - cs.id = c.commonExprInc - c.commonExpr[cs.id] = subExpr - c.commonExprInc += 1 - } cs.cnt = cs.cnt + 1 } } @@ -357,9 +349,15 @@ func (c *compiler) emitSubExpr(subExpr string, loc file.Location) { func (c *compiler) needCacheCommon(n ast.Node) (bool, int) { needCacheCommon, exprUniqId := false, -1 if c.exprRecords != nil { - hash := fmt.Sprintf("%x", sha1.Sum([]byte(n.SubExpr()))) + expr := n.SubExpr() + hash := fmt.Sprintf("%x", sha1.Sum([]byte(expr))) cs, ok := c.exprRecords[hash] if ok && cs.cnt > 1 { + if cs.id == -1 { + cs.id = c.commonExprInc + c.commonExpr[cs.id] = expr + c.commonExprInc += 1 + } needCacheCommon = true exprUniqId = cs.id } From b9f3790664e3fecd1e65f429b5f60c114647b1e4 Mon Sep 17 00:00:00 2001 From: zhuliquan Date: Mon, 24 Jul 2023 15:49:59 +0800 Subject: [PATCH 04/11] feature: mv common cache to vm --- compiler/compiler.go | 1 - vm/program.go | 17 ++++++++--------- vm/vm.go | 23 ++++++++++------------- 3 files changed, 18 insertions(+), 23 deletions(-) diff --git a/compiler/compiler.go b/compiler/compiler.go index 7b7f5fff7..757fc6839 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -39,7 +39,6 @@ func Compile(tree *parser.Tree, config *conf.Config) (program *Program, err erro c.countCommonExpr(tree.Node) defer func() { program.CommonExpr = c.commonExpr - program.CommonCache = make([]interface{}, len(c.commonExpr)) }() } } diff --git a/vm/program.go b/vm/program.go index 6eaf22dfd..7780930dd 100644 --- a/vm/program.go +++ b/vm/program.go @@ -15,15 +15,14 @@ import ( ) type Program struct { - Node ast.Node - Source *file.Source - Locations []file.Location - Constants []interface{} - Bytecode []Opcode - Arguments []int - Functions []Function - CommonExpr map[int]string - CommonCache []interface{} + Node ast.Node + Source *file.Source + Locations []file.Location + Constants []interface{} + Bytecode []Opcode + Arguments []int + Functions []Function + CommonExpr map[int]string } func (program *Program) Disassemble() string { diff --git a/vm/vm.go b/vm/vm.go index 9a9714313..d2ee41a3b 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -41,6 +41,7 @@ type VM struct { curr chan int memory int memoryBudget int + commonCache map[int]interface{} } type Scope struct { @@ -82,9 +83,9 @@ func (vm *VM) Run(program *Program, env interface{}) (_ interface{}, err error) } else { vm.scopes = vm.scopes[0:0] } - - for i := 0; i < len(program.CommonCache); i++ { - program.CommonCache[i] = _notSave + vm.commonCache = make(map[int]interface{}, len(program.CommonExpr)) + for i := 0; i < len(vm.commonCache); i++ { + vm.commonCache[i] = _notSave } vm.memoryBudget = MemoryBudget vm.memory = 0 @@ -126,12 +127,10 @@ func (vm *VM) Run(program *Program, env interface{}) (_ interface{}, err error) vm.push(runtime.Fetch(a, b)) case OpFetchField: - a := vm.pop() - vm.push(runtime.FetchField(a, program.Constants[arg].(*runtime.Field))) + vm.push(runtime.FetchField(vm.pop(), program.Constants[arg].(*runtime.Field))) case OpMethod: - a := vm.pop() - vm.push(runtime.FetchMethod(a, program.Constants[arg].(*runtime.Method))) + vm.push(runtime.FetchMethod(vm.pop(), program.Constants[arg].(*runtime.Method))) case OpTrue: vm.push(true) @@ -143,12 +142,10 @@ func (vm *VM) Run(program *Program, env interface{}) (_ interface{}, err error) vm.push(nil) case OpNegate: - v := runtime.Negate(vm.pop()) - vm.push(v) + vm.push(runtime.Negate(vm.pop())) case OpNot: - v := vm.pop().(bool) - vm.push(!v) + vm.push(!(vm.pop().(bool))) case OpEqual: b := vm.pop() @@ -451,10 +448,10 @@ func (vm *VM) Run(program *Program, env interface{}) (_ interface{}, err error) vm.push(scope.Array.Index(scope.It).Interface()) case OpSaveCommon: - program.CommonCache[arg] = vm.current() + vm.commonCache[arg] = vm.current() case OpLoadCommon: - vm.push(program.CommonCache[arg]) + vm.push(vm.commonCache[arg]) case OpBegin: a := vm.pop() From 716ed87b9a6162ee870b97aabdd5c10759593607 Mon Sep 17 00:00:00 2001 From: zhuliquan Date: Mon, 24 Jul 2023 16:27:23 +0800 Subject: [PATCH 05/11] feature: using []interface{} for commonCache --- vm/vm.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vm/vm.go b/vm/vm.go index d2ee41a3b..a7b06e52a 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -41,7 +41,7 @@ type VM struct { curr chan int memory int memoryBudget int - commonCache map[int]interface{} + commonCache []interface{} } type Scope struct { @@ -83,7 +83,7 @@ func (vm *VM) Run(program *Program, env interface{}) (_ interface{}, err error) } else { vm.scopes = vm.scopes[0:0] } - vm.commonCache = make(map[int]interface{}, len(program.CommonExpr)) + vm.commonCache = make([]interface{}, len(program.CommonExpr)) for i := 0; i < len(vm.commonCache); i++ { vm.commonCache[i] = _notSave } From 1ae932912fed344774a93f64d808342c656f8072 Mon Sep 17 00:00:00 2001 From: zhuliquan Date: Tue, 25 Jul 2023 00:51:34 +0800 Subject: [PATCH 06/11] test: analysis common --- .../{check_common.go => analysis_common.go} | 124 ++++----- compiler/analysis_common_test.go | 263 ++++++++++++++++++ compiler/compiler.go | 6 +- 3 files changed, 328 insertions(+), 65 deletions(-) rename compiler/{check_common.go => analysis_common.go} (69%) create mode 100644 compiler/analysis_common_test.go diff --git a/compiler/check_common.go b/compiler/analysis_common.go similarity index 69% rename from compiler/check_common.go rename to compiler/analysis_common.go index 6b859c6d1..64ec99c60 100644 --- a/compiler/check_common.go +++ b/compiler/analysis_common.go @@ -11,46 +11,46 @@ import ( "github.com/antonmedv/expr/file" ) -func (c *compiler) countCommonExpr(node ast.Node) { +func (c *compiler) analyzeCommonExpr(node ast.Node) { switch n := node.(type) { case *ast.NilNode: - c.commonCommonNilNode(n) + c.analyzeCommonNilNode(n) case *ast.IdentifierNode: - c.countCommonIdentifierNode(n) + c.analyzeCommonIdentifierNode(n) case *ast.IntegerNode: - c.countCommonIntegerNode(n) + c.analyzeCommonIntegerNode(n) case *ast.FloatNode: - c.countCommonFloatNode(n) + c.analyzeCommonFloatNode(n) case *ast.BoolNode: - c.countCommonBoolNode(n) + c.analyzeCommonBoolNode(n) case *ast.StringNode: - c.countCommonStringNode(n) + c.analyzeCommonStringNode(n) case *ast.ConstantNode: - c.countCommonConstantNode(n) + c.analyzeCommonConstantNode(n) case *ast.UnaryNode: - c.countCommonUnaryNode(n) + c.analyzeCommonUnaryNode(n) case *ast.BinaryNode: - c.countCommonBinaryNode(n) + c.analyzeCommonBinaryNode(n) case *ast.ChainNode: - c.countCommonChainNode(n) + c.analyzeCommonChainNode(n) case *ast.MemberNode: - c.countCommonMemberNode(n) + c.analyzeCommonMemberNode(n) case *ast.SliceNode: - c.countCommonSliceNode(n) + c.analyzeCommonSliceNode(n) case *ast.CallNode: c.checkCallNode(n) case *ast.BuiltinNode: - c.countCommonBuiltinNode(n) + c.analyzeCommonBuiltinNode(n) case *ast.ClosureNode: - c.countCommonClosureNode(n) + c.analyzeCommonClosureNode(n) case *ast.PointerNode: - c.countCommonPointerNode(n) + c.analyzeCommonPointerNode(n) case *ast.ConditionalNode: - c.countCommonConditionalNode(n) + c.analyzeCommonConditionalNode(n) case *ast.ArrayNode: - c.countCommonArrayNode(n) + c.analyzeCommonArrayNode(n) case *ast.MapNode: - c.countCommonMapNode(n) + c.analyzeCommonMapNode(n) case *ast.PairNode: // do nothing default: @@ -58,31 +58,31 @@ func (c *compiler) countCommonExpr(node ast.Node) { } } -func (c *compiler) commonCommonNilNode(n *ast.NilNode) { +func (c *compiler) analyzeCommonNilNode(n *ast.NilNode) { n.SetSubExpr("nil") } -func (c *compiler) countCommonIdentifierNode(n *ast.IdentifierNode) { +func (c *compiler) analyzeCommonIdentifierNode(n *ast.IdentifierNode) { n.SetSubExpr(n.Value) } -func (c *compiler) countCommonIntegerNode(n *ast.IntegerNode) { +func (c *compiler) analyzeCommonIntegerNode(n *ast.IntegerNode) { n.SetSubExpr(strconv.FormatInt(int64(n.Value), 10)) } -func (c *compiler) countCommonFloatNode(n *ast.FloatNode) { +func (c *compiler) analyzeCommonFloatNode(n *ast.FloatNode) { n.SetSubExpr(strconv.FormatFloat(n.Value, 'f', 10, 64)) } -func (c *compiler) countCommonBoolNode(n *ast.BoolNode) { +func (c *compiler) analyzeCommonBoolNode(n *ast.BoolNode) { n.SetSubExpr(strconv.FormatBool(n.Value)) } -func (c *compiler) countCommonStringNode(n *ast.StringNode) { +func (c *compiler) analyzeCommonStringNode(n *ast.StringNode) { n.SetSubExpr(strconv.Quote(n.Value)) } -func (c *compiler) countCommonConstantNode(n *ast.ConstantNode) { +func (c *compiler) analyzeCommonConstantNode(n *ast.ConstantNode) { var s string switch n.Value.(type) { case string: @@ -117,8 +117,8 @@ func (c *compiler) countCommonConstantNode(n *ast.ConstantNode) { n.SetSubExpr(s) } -func (c *compiler) countCommonUnaryNode(n *ast.UnaryNode) { - c.countCommonExpr(n.Node) +func (c *compiler) analyzeCommonUnaryNode(n *ast.UnaryNode) { + c.analyzeCommonExpr(n.Node) buf := strings.Builder{} switch n.Operator { case "+": @@ -133,9 +133,9 @@ func (c *compiler) countCommonUnaryNode(n *ast.UnaryNode) { n.SetSubExpr(buf.String()) } -func (c *compiler) countCommonBinaryNode(n *ast.BinaryNode) { - c.countCommonExpr(n.Left) - c.countCommonExpr(n.Right) +func (c *compiler) analyzeCommonBinaryNode(n *ast.BinaryNode) { + c.analyzeCommonExpr(n.Left) + c.analyzeCommonExpr(n.Right) ls := n.Left.SubExpr() rs := n.Right.SubExpr() @@ -185,17 +185,17 @@ func (c *compiler) countCommonBinaryNode(n *ast.BinaryNode) { case "??", "and", "or", "||", "&&": // do nothing default: - c.emitSubExpr(n.SubExpr(), n.Location()) + c.countCommonExpr(n.SubExpr(), n.Location()) } } -func (c *compiler) countCommonChainNode(n *ast.ChainNode) { - c.countCommonExpr(n.Node) +func (c *compiler) analyzeCommonChainNode(n *ast.ChainNode) { + c.analyzeCommonExpr(n.Node) n.SetSubExpr(n.Node.SubExpr()) } -func (c *compiler) countCommonMemberNode(n *ast.MemberNode) { - c.countCommonExpr(n.Node) +func (c *compiler) analyzeCommonMemberNode(n *ast.MemberNode) { + c.analyzeCommonExpr(n.Node) buf := strings.Builder{} buf.WriteString(n.Node.SubExpr()) if n.Method { @@ -209,7 +209,7 @@ func (c *compiler) countCommonMemberNode(n *ast.MemberNode) { buf.WriteString(".") buf.WriteString(n.Name) } else { - c.countCommonExpr(n.Property) + c.analyzeCommonExpr(n.Property) buf.WriteString("[") buf.WriteString(n.Property.SubExpr()) buf.WriteString("]") @@ -218,19 +218,19 @@ func (c *compiler) countCommonMemberNode(n *ast.MemberNode) { n.SetSubExpr(buf.String()) } -func (c *compiler) countCommonSliceNode(n *ast.SliceNode) { +func (c *compiler) analyzeCommonSliceNode(n *ast.SliceNode) { buf := strings.Builder{} - c.countCommonExpr(n.Node) + c.analyzeCommonExpr(n.Node) buf.WriteString(n.Node.SubExpr()) buf.WriteString("[") toStr := "" fromStr := "" if n.To != nil { - c.countCommonExpr(n.To) + c.analyzeCommonExpr(n.To) toStr = n.To.SubExpr() } if n.From != nil { - c.countCommonExpr(n.From) + c.analyzeCommonExpr(n.From) fromStr = n.From.SubExpr() } buf.WriteString(fromStr) @@ -242,11 +242,11 @@ func (c *compiler) countCommonSliceNode(n *ast.SliceNode) { func (c *compiler) checkCallNode(n *ast.CallNode) { buf := strings.Builder{} - c.countCommonExpr(n.Callee) + c.analyzeCommonExpr(n.Callee) buf.WriteString(n.Callee.SubExpr()) buf.WriteString("(") for i, arg := range n.Arguments { - c.countCommonExpr(arg) + c.analyzeCommonExpr(arg) if i != 0 { buf.WriteString(",") } @@ -256,12 +256,12 @@ func (c *compiler) checkCallNode(n *ast.CallNode) { n.SetSubExpr(buf.String()) } -func (c *compiler) countCommonBuiltinNode(n *ast.BuiltinNode) { +func (c *compiler) analyzeCommonBuiltinNode(n *ast.BuiltinNode) { buf := strings.Builder{} buf.WriteString(n.Name) buf.WriteString("(") for i, arg := range n.Arguments { - c.countCommonExpr(arg) + c.analyzeCommonExpr(arg) if i != 0 { buf.WriteString(",") } @@ -271,21 +271,21 @@ func (c *compiler) countCommonBuiltinNode(n *ast.BuiltinNode) { n.SetSubExpr(buf.String()) } -func (c *compiler) countCommonClosureNode(n *ast.ClosureNode) { - c.countCommonExpr(n.Node) +func (c *compiler) analyzeCommonClosureNode(n *ast.ClosureNode) { + c.analyzeCommonExpr(n.Node) // omit '{' / '}' n.SetSubExpr(n.Node.SubExpr()) } -func (c *compiler) countCommonPointerNode(n *ast.PointerNode) { +func (c *compiler) analyzeCommonPointerNode(n *ast.PointerNode) { // do nothing n.SetSubExpr("#") } -func (c *compiler) countCommonConditionalNode(n *ast.ConditionalNode) { - c.countCommonExpr(n.Cond) - c.countCommonExpr(n.Exp1) - c.countCommonExpr(n.Exp2) +func (c *compiler) analyzeCommonConditionalNode(n *ast.ConditionalNode) { + c.analyzeCommonExpr(n.Cond) + c.analyzeCommonExpr(n.Exp1) + c.analyzeCommonExpr(n.Exp2) buf := strings.Builder{} buf.WriteString(n.Cond.SubExpr()) buf.WriteString(" ? ") @@ -295,11 +295,11 @@ func (c *compiler) countCommonConditionalNode(n *ast.ConditionalNode) { n.SetSubExpr(buf.String()) } -func (c *compiler) countCommonArrayNode(n *ast.ArrayNode) { +func (c *compiler) analyzeCommonArrayNode(n *ast.ArrayNode) { buf := strings.Builder{} buf.WriteString("[") for i, node := range n.Nodes { - c.countCommonExpr(node) + c.analyzeCommonExpr(node) if i != 0 { buf.WriteString(",") } @@ -309,12 +309,12 @@ func (c *compiler) countCommonArrayNode(n *ast.ArrayNode) { n.SetSubExpr(buf.String()) } -func (c *compiler) countCommonMapNode(n *ast.MapNode) { +func (c *compiler) analyzeCommonMapNode(n *ast.MapNode) { pairs := make([]*ast.PairNode, 0) for i := range n.Pairs { pair := n.Pairs[i].(*ast.PairNode) - c.countCommonExpr(pair.Key) - c.countCommonExpr(pair.Value) + c.analyzeCommonExpr(pair.Key) + c.analyzeCommonExpr(pair.Value) pairs = append(pairs, pair) } sort.Slice(pairs, func(i, j int) bool { @@ -334,7 +334,7 @@ func (c *compiler) countCommonMapNode(n *ast.MapNode) { n.SetSubExpr(buf.String()) } -func (c *compiler) emitSubExpr(subExpr string, loc file.Location) { +func (c *compiler) countCommonExpr(subExpr string, loc file.Location) { if c.exprRecords == nil || subExpr == "" { return } @@ -346,8 +346,8 @@ func (c *compiler) emitSubExpr(subExpr string, loc file.Location) { } } -func (c *compiler) needCacheCommon(n ast.Node) (bool, int) { - needCacheCommon, exprUniqId := false, -1 +func (c *compiler) needReuseCommon(n ast.Node) (bool, int) { + needReuseCommon, exprUniqId := false, -1 if c.exprRecords != nil { expr := n.SubExpr() hash := fmt.Sprintf("%x", sha1.Sum([]byte(expr))) @@ -358,9 +358,9 @@ func (c *compiler) needCacheCommon(n ast.Node) (bool, int) { c.commonExpr[cs.id] = expr c.commonExprInc += 1 } - needCacheCommon = true + needReuseCommon = true exprUniqId = cs.id } } - return needCacheCommon, exprUniqId + return needReuseCommon, exprUniqId } diff --git a/compiler/analysis_common_test.go b/compiler/analysis_common_test.go new file mode 100644 index 000000000..c809fd8b5 --- /dev/null +++ b/compiler/analysis_common_test.go @@ -0,0 +1,263 @@ +package compiler_test + +import ( + "testing" + + "github.com/antonmedv/expr" + "github.com/antonmedv/expr/vm" + "github.com/stretchr/testify/assert" +) + +func TestAnalyzeCommonExpr(t *testing.T) { + type testCase struct { + input string + expr string + program *vm.Program + } + for _, tt := range []testCase{ + { + input: `(1+1) == 2 and 2 == (1 + 1)`, + expr: `((1 + 1) == 2) and ((1 + 1) == 2)`, + program: &vm.Program{ + Bytecode: []vm.Opcode{ + vm.OpLoadCommon, + vm.OpJumpIfSaveCommon, + vm.OpPop, + vm.OpLoadCommon, + vm.OpJumpIfSaveCommon, + vm.OpPop, + vm.OpPush, + vm.OpPush, + vm.OpAdd, + vm.OpSaveCommon, + vm.OpPush, + vm.OpEqualInt, + vm.OpSaveCommon, + vm.OpJumpIfFalse, + vm.OpPop, + vm.OpLoadCommon, + vm.OpJumpIfSaveCommon, + vm.OpPop, + vm.OpPush, + vm.OpLoadCommon, + vm.OpJumpIfSaveCommon, + vm.OpPop, + vm.OpPush, + vm.OpPush, + vm.OpAdd, + vm.OpSaveCommon, + vm.OpEqualInt, + vm.OpSaveCommon, + }, + Arguments: []int{ + 0, 11, 0, 1, 5, 0, 0, 0, 0, 1, 1, 0, 0, + 14, 0, + 0, 11, 0, 1, 1, 5, 0, 0, 0, 0, 1, 0, 0, + }, + }, + }, + { + input: `not ((+(1+1)) ** 2 == 4 or 4 == (-(1 + 1)) ^ 2)`, + expr: `not (((-(1 + 1) ** 2) == 4) or ((1 + 1) ** 2) == 4))`, + program: &vm.Program{ + Bytecode: []vm.Opcode{ + vm.OpLoadCommon, + vm.OpJumpIfSaveCommon, + vm.OpPop, + vm.OpPush, + vm.OpPush, + vm.OpAdd, + vm.OpSaveCommon, + vm.OpPush, + vm.OpExponent, + vm.OpPush, + vm.OpEqual, + vm.OpJumpIfTrue, + vm.OpPop, + vm.OpPush, + vm.OpLoadCommon, + vm.OpJumpIfSaveCommon, + vm.OpPop, + vm.OpPush, + vm.OpPush, + vm.OpAdd, + vm.OpSaveCommon, + vm.OpNegate, + vm.OpPush, + vm.OpExponent, + vm.OpEqual, + vm.OpNot, + }, + Arguments: []int{ + 0, 5, 0, 0, 0, 0, 0, 1, 0, 2, 0, 13, 0, 2, + 0, 5, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + }, + }, + }, + { + input: `nil == nil`, + expr: `nil == nil`, + program: &vm.Program{ + Bytecode: []vm.Opcode{ + vm.OpNil, + vm.OpNil, + vm.OpEqual, + }, + Arguments: []int{0, 0, 0}, + }, + }, + { + input: `true && (true || false)`, + expr: `(false or true) and true`, + program: &vm.Program{ + Bytecode: []vm.Opcode{ + vm.OpTrue, + vm.OpJumpIfFalse, + vm.OpPop, + vm.OpTrue, + vm.OpJumpIfTrue, + vm.OpPop, + vm.OpFalse, + }, + Arguments: []int{0, 5, 0, 0, 2, 0, 0}, + }, + }, + { + input: `1 >= 2 and 2 < 1`, + expr: `(2 < 1) and (2 < 1)`, + program: &vm.Program{ + Bytecode: []vm.Opcode{ + vm.OpLoadCommon, + vm.OpJumpIfSaveCommon, + vm.OpPop, + vm.OpPush, + vm.OpPush, + vm.OpMoreOrEqual, + vm.OpSaveCommon, + vm.OpJumpIfFalse, + vm.OpPop, + vm.OpLoadCommon, + vm.OpJumpIfSaveCommon, + vm.OpPop, + vm.OpPush, + vm.OpPush, + vm.OpLess, + vm.OpSaveCommon, + }, + Arguments: []int{0, 5, 0, 0, 1, 0, 0, 8, 0, 0, 5, 0, 1, 0, 0, 0}, + }, + }, + { + input: `1 <= 2 and 2 > 1`, + expr: `(2 > 1) and (2 > 1)`, + program: &vm.Program{ + Bytecode: []vm.Opcode{ + vm.OpLoadCommon, + vm.OpJumpIfSaveCommon, + vm.OpPop, + vm.OpPush, + vm.OpPush, + vm.OpLessOrEqual, + vm.OpSaveCommon, + vm.OpJumpIfFalse, + vm.OpPop, + vm.OpLoadCommon, + vm.OpJumpIfSaveCommon, + vm.OpPop, + vm.OpPush, + vm.OpPush, + vm.OpMore, + vm.OpSaveCommon, + }, + Arguments: []int{0, 5, 0, 0, 1, 0, 0, 8, 0, 0, 5, 0, 1, 0, 0, 0}, + }, + }, + { + input: `A.B.C.D`, + expr: "A.B.C.D", + program: &vm.Program{ + Bytecode: []vm.Opcode{ + vm.OpLoadField, + }, + Arguments: []int{0}, + }, + }, + { + input: `A?.B.C.D`, + expr: "A?.B.C.D", + program: &vm.Program{ + Bytecode: []vm.Opcode{ + vm.OpLoadField, + vm.OpJumpIfNil, + vm.OpFetchField, + }, + Arguments: []int{0, 1, 1}, + }, + }, + { + input: `A.B?.C.D`, + expr: "A.B?.C.D", + program: &vm.Program{ + Bytecode: []vm.Opcode{ + vm.OpLoadField, + vm.OpJumpIfNil, + vm.OpFetchField, + }, + Arguments: []int{0, 1, 1}, + }, + }, + { + input: `A.Map["B"].C.D`, + expr: "A.Map[\"B\"].C.D", + program: &vm.Program{ + Bytecode: []vm.Opcode{ + vm.OpLoadField, + vm.OpPush, + vm.OpFetch, + vm.OpFetchField, + }, + Arguments: []int{0, 1, 0, 2}, + }, + }, + { + input: `A ?? 1`, + expr: "A ?? 1", + program: &vm.Program{ + Bytecode: []vm.Opcode{ + vm.OpLoadField, + vm.OpJumpIfNotNil, + vm.OpPop, + vm.OpPush, + }, + Arguments: []int{0, 2, 0, 1}, + }, + }, + { + input: `int("123") == int("123")`, + expr: `int("123") == int("123")`, + program: &vm.Program{ + Bytecode: []vm.Opcode{ + vm.OpPush, + vm.OpBuiltin, + vm.OpPush, + vm.OpBuiltin, + vm.OpEqualInt, + }, + Arguments: []int{0, 3, 0, 3, 0}, + }, + }, + } { + t.Run(tt.input, func(t *testing.T) { + program, err := expr.Compile(tt.input, expr.Env(Env{}), expr.Optimize(false), expr.AllowReuseCommon(true)) + if err != nil { + assert.Nil(t, err) + } else { + assert.Equal(t, tt.expr, program.Node.SubExpr()) + assert.Equal(t, tt.program.Bytecode, program.Bytecode) + assert.Equal(t, tt.program.Arguments, program.Arguments) + } + + }) + } + +} diff --git a/compiler/compiler.go b/compiler/compiler.go index 757fc6839..563841768 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -36,7 +36,7 @@ func Compile(tree *parser.Tree, config *conf.Config) (program *Program, err erro c.commonExprInc = 0 c.commonExpr = make(map[int]string) c.exprRecords = make(map[string]*exprRecord) - c.countCommonExpr(tree.Node) + c.analyzeCommonExpr(tree.Node) defer func() { program.CommonExpr = c.commonExpr }() @@ -320,7 +320,7 @@ func (c *compiler) UnaryNode(node *ast.UnaryNode) { } func (c *compiler) BinaryNode(node *ast.BinaryNode) { - if needCacheResult, exprUniqId := c.needCacheCommon(node); needCacheResult { + if needReuseCommon, exprUniqId := c.needReuseCommon(node); needReuseCommon { c.emit(OpLoadCommon, exprUniqId) cEnd := c.emit(OpJumpIfSaveCommon, placeholder) c.emit(OpPop) @@ -562,7 +562,7 @@ func (c *compiler) SliceNode(node *ast.SliceNode) { } func (c *compiler) CallNode(node *ast.CallNode) { - if needCacheResult, exprUniqId := c.needCacheCommon(node); needCacheResult { + if needReuseCommon, exprUniqId := c.needReuseCommon(node); needReuseCommon { c.emit(OpLoadCommon, exprUniqId) cEnd := c.emit(OpJumpIfSaveCommon, placeholder) c.emit(OpPop) From 2c57e2e1685f803c9276409b75c66636dc39cb73 Mon Sep 17 00:00:00 2001 From: zhuliquan Date: Wed, 26 Jul 2023 11:04:44 +0800 Subject: [PATCH 07/11] Update vm.go fix: extract commonCache to temp variable in vm.go --- vm/vm.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/vm/vm.go b/vm/vm.go index b5f186732..3ceaeeea3 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -41,7 +41,6 @@ type VM struct { curr chan int memory int memoryBudget int - commonCache []interface{} } type Scope struct { @@ -83,9 +82,9 @@ func (vm *VM) Run(program *Program, env interface{}) (_ interface{}, err error) } else { vm.scopes = vm.scopes[0:0] } - vm.commonCache = make([]interface{}, len(program.CommonExpr)) - for i := 0; i < len(vm.commonCache); i++ { - vm.commonCache[i] = _notSave + commonCache := make([]interface{}, len(program.CommonExpr)) + for i := 0; i < len(commonCache); i++ { + commonCache[i] = _notSave } vm.memoryBudget = MemoryBudget vm.memory = 0 @@ -455,10 +454,10 @@ func (vm *VM) Run(program *Program, env interface{}) (_ interface{}, err error) vm.push(scope.Array.Index(scope.It).Interface()) case OpSaveCommon: - vm.commonCache[arg] = vm.current() + commonCache[arg] = vm.current() case OpLoadCommon: - vm.push(vm.commonCache[arg]) + vm.push(commonCache[arg]) case OpBegin: a := vm.pop() From a248074a2bcecc3caca3354d7beeb9ed5a151493 Mon Sep 17 00:00:00 2001 From: zhuliquan Date: Wed, 26 Jul 2023 23:16:41 +0800 Subject: [PATCH 08/11] feature: for readable and recover scopes init --- vm/vm.go | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/vm/vm.go b/vm/vm.go index 3ceaeeea3..9b96b03ac 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -77,9 +77,7 @@ func (vm *VM) Run(program *Program, env interface{}) (_ interface{}, err error) } else { vm.stack = vm.stack[0:0] } - if vm.scopes == nil { - vm.scopes = make([]*Scope, 0, 64) - } else { + if vm.scopes != nil { vm.scopes = vm.scopes[0:0] } commonCache := make([]interface{}, len(program.CommonExpr)) @@ -130,13 +128,15 @@ func (vm *VM) Run(program *Program, env interface{}) (_ interface{}, err error) vm.push(runtime.Fetch(a, b)) case OpFetchField: - vm.push(runtime.FetchField(vm.pop(), program.Constants[arg].(*runtime.Field))) + a := vm.pop() + vm.push(runtime.FetchField(a, program.Constants[arg].(*runtime.Field))) case OpLoadEnv: vm.push(env) case OpMethod: - vm.push(runtime.FetchMethod(vm.pop(), program.Constants[arg].(*runtime.Method))) + a := vm.pop() + vm.push(runtime.FetchMethod(a, program.Constants[arg].(*runtime.Method))) case OpTrue: vm.push(true) @@ -148,10 +148,12 @@ func (vm *VM) Run(program *Program, env interface{}) (_ interface{}, err error) vm.push(nil) case OpNegate: - vm.push(runtime.Negate(vm.pop())) + a := vm.pop() + vm.push(runtime.Negate(a)) case OpNot: - vm.push(!(vm.pop().(bool))) + a := vm.pop().(bool) + vm.push(!a) case OpEqual: b := vm.pop() From c487137f38142b400be2e63af3c809e14dd46bb9 Mon Sep 17 00:00:00 2001 From: zhuliquan Date: Thu, 27 Jul 2023 00:50:47 +0800 Subject: [PATCH 09/11] test: more case for analysis_common --- compiler/analysis_common_test.go | 112 +++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/compiler/analysis_common_test.go b/compiler/analysis_common_test.go index c809fd8b5..60800133d 100644 --- a/compiler/analysis_common_test.go +++ b/compiler/analysis_common_test.go @@ -246,6 +246,118 @@ func TestAnalyzeCommonExpr(t *testing.T) { Arguments: []int{0, 3, 0, 3, 0}, }, }, + { + input: `true ? 1 : 2`, + expr: "true ? 1 : 2", + program: &vm.Program{ + Bytecode: []vm.Opcode{ + vm.OpTrue, + vm.OpJumpIfFalse, + vm.OpPop, + vm.OpPush, + vm.OpJump, + vm.OpPop, + vm.OpPush, + }, + Arguments: []int{0, 3, 0, 0, 2, 0, 1}, + }, + }, + { + input: `[true, true, false, 1.7]`, + expr: `[true,true,false,1.7000000000]`, + program: &vm.Program{ + Constants: []interface{}{1.7, 4}, + Bytecode: []vm.Opcode{ + vm.OpTrue, + vm.OpTrue, + vm.OpFalse, + vm.OpPush, + vm.OpPush, + vm.OpArray, + }, + Arguments: []int{0, 0, 0, 0, 1, 0}, + }, + }, + { + input: `{1: true, 2: true, 3: false, 4: 1.7}`, + expr: `{"1":true,"2":true,"3":false,"4":1.7000000000}`, + program: &vm.Program{ + Constants: []interface{}{1.7, 4}, + Bytecode: []vm.Opcode{ + vm.OpPush, + vm.OpTrue, + vm.OpPush, + vm.OpTrue, + vm.OpPush, + vm.OpFalse, + vm.OpPush, + vm.OpPush, + vm.OpPush, + vm.OpMap, + }, + Arguments: []int{0, 0, 1, 0, 2, 0, 3, 4, 5, 0}, + }, + }, + { + input: `all([true, false], { # })`, + expr: `all([true,false],#)`, + program: &vm.Program{ + Constants: []interface{}{1.7, 4}, + Bytecode: []vm.Opcode{ + vm.OpTrue, + vm.OpFalse, + vm.OpPush, + vm.OpArray, + vm.OpBegin, + vm.OpJumpIfEnd, + vm.OpPointer, + vm.OpJumpIfFalse, + vm.OpPop, + vm.OpIncrementIt, + vm.OpJumpBackward, + vm.OpTrue, + vm.OpEnd, + }, + Arguments: []int{0, 0, 0, 0, 0, 5, 0, 4, 0, 0, 6, 0, 0}, + }, + }, + { + input: `any([1+1, 1+1], { # > 1 })`, + expr: `any([1 + 1,1 + 1],# > 1)`, + program: &vm.Program{ + Constants: []interface{}{1.7, 4}, + Bytecode: []vm.Opcode{ + vm.OpLoadCommon, + vm.OpJumpIfSaveCommon, + vm.OpPop, + vm.OpPush, + vm.OpPush, + vm.OpAdd, + vm.OpSaveCommon, + vm.OpLoadCommon, + vm.OpJumpIfSaveCommon, + vm.OpPop, + vm.OpPush, + vm.OpPush, + vm.OpAdd, + vm.OpSaveCommon, + vm.OpPush, + vm.OpArray, + vm.OpBegin, + vm.OpJumpIfEnd, + vm.OpPointer, + vm.OpPush, + vm.OpMore, + vm.OpJumpIfTrue, + vm.OpPop, + vm.OpIncrementIt, + vm.OpJumpBackward, + vm.OpFalse, + vm.OpEnd, + }, + Arguments: []int{0, 5, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 1, 0, 0, 7, 0, 0, 0, 4, 0, 0, 8, 0, 0}, + }, + }, } { t.Run(tt.input, func(t *testing.T) { program, err := expr.Compile(tt.input, expr.Env(Env{}), expr.Optimize(false), expr.AllowReuseCommon(true)) From 1be481132017d10f08ac275c44fbd764f5f6632e Mon Sep 17 00:00:00 2001 From: zhuliquan Date: Thu, 27 Jul 2023 01:41:13 +0800 Subject: [PATCH 10/11] feature: avoid check at common first occur --- compiler/analysis_common.go | 10 +++--- compiler/analysis_common_test.go | 62 +++++++++++++++++++------------- compiler/compiler.go | 39 +++++++++++++------- 3 files changed, 70 insertions(+), 41 deletions(-) diff --git a/compiler/analysis_common.go b/compiler/analysis_common.go index 64ec99c60..e71066aa6 100644 --- a/compiler/analysis_common.go +++ b/compiler/analysis_common.go @@ -254,6 +254,7 @@ func (c *compiler) checkCallNode(n *ast.CallNode) { } buf.WriteString(")") n.SetSubExpr(buf.String()) + c.countCommonExpr(n.SubExpr(), n.Location()) } func (c *compiler) analyzeCommonBuiltinNode(n *ast.BuiltinNode) { @@ -340,14 +341,14 @@ func (c *compiler) countCommonExpr(subExpr string, loc file.Location) { } hash := fmt.Sprintf("%x", sha1.Sum([]byte(subExpr))) if cs, ok := c.exprRecords[hash]; !ok { - c.exprRecords[hash] = &exprRecord{cnt: 1, id: -1} + c.exprRecords[hash] = &exprRecord{cnt: 1, loc: loc, id: -1} } else { cs.cnt = cs.cnt + 1 } } -func (c *compiler) needReuseCommon(n ast.Node) (bool, int) { - needReuseCommon, exprUniqId := false, -1 +func (c *compiler) needReuseCommon(n ast.Node) (bool, bool, int) { + needReuseCommon, isFirstOccur, exprUniqId := false, false, -1 if c.exprRecords != nil { expr := n.SubExpr() hash := fmt.Sprintf("%x", sha1.Sum([]byte(expr))) @@ -359,8 +360,9 @@ func (c *compiler) needReuseCommon(n ast.Node) (bool, int) { c.commonExprInc += 1 } needReuseCommon = true + isFirstOccur = n.Location().Line == cs.loc.Line && n.Location().Column == cs.loc.Column exprUniqId = cs.id } } - return needReuseCommon, exprUniqId + return needReuseCommon, isFirstOccur, exprUniqId } diff --git a/compiler/analysis_common_test.go b/compiler/analysis_common_test.go index 60800133d..0a0c69b8d 100644 --- a/compiler/analysis_common_test.go +++ b/compiler/analysis_common_test.go @@ -20,12 +20,6 @@ func TestAnalyzeCommonExpr(t *testing.T) { expr: `((1 + 1) == 2) and ((1 + 1) == 2)`, program: &vm.Program{ Bytecode: []vm.Opcode{ - vm.OpLoadCommon, - vm.OpJumpIfSaveCommon, - vm.OpPop, - vm.OpLoadCommon, - vm.OpJumpIfSaveCommon, - vm.OpPop, vm.OpPush, vm.OpPush, vm.OpAdd, @@ -50,7 +44,7 @@ func TestAnalyzeCommonExpr(t *testing.T) { vm.OpSaveCommon, }, Arguments: []int{ - 0, 11, 0, 1, 5, 0, 0, 0, 0, 1, 1, 0, 0, + 0, 0, 0, 1, 1, 0, 0, 14, 0, 0, 11, 0, 1, 1, 5, 0, 0, 0, 0, 1, 0, 0, }, @@ -61,9 +55,6 @@ func TestAnalyzeCommonExpr(t *testing.T) { expr: `not (((-(1 + 1) ** 2) == 4) or ((1 + 1) ** 2) == 4))`, program: &vm.Program{ Bytecode: []vm.Opcode{ - vm.OpLoadCommon, - vm.OpJumpIfSaveCommon, - vm.OpPop, vm.OpPush, vm.OpPush, vm.OpAdd, @@ -89,7 +80,7 @@ func TestAnalyzeCommonExpr(t *testing.T) { vm.OpNot, }, Arguments: []int{ - 0, 5, 0, 0, 0, 0, 0, 1, 0, 2, 0, 13, 0, 2, + 0, 0, 0, 0, 1, 0, 2, 0, 13, 0, 2, 0, 5, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, }, }, @@ -127,9 +118,6 @@ func TestAnalyzeCommonExpr(t *testing.T) { expr: `(2 < 1) and (2 < 1)`, program: &vm.Program{ Bytecode: []vm.Opcode{ - vm.OpLoadCommon, - vm.OpJumpIfSaveCommon, - vm.OpPop, vm.OpPush, vm.OpPush, vm.OpMoreOrEqual, @@ -144,7 +132,7 @@ func TestAnalyzeCommonExpr(t *testing.T) { vm.OpLess, vm.OpSaveCommon, }, - Arguments: []int{0, 5, 0, 0, 1, 0, 0, 8, 0, 0, 5, 0, 1, 0, 0, 0}, + Arguments: []int{0, 1, 0, 0, 8, 0, 0, 5, 0, 1, 0, 0, 0}, }, }, { @@ -152,9 +140,6 @@ func TestAnalyzeCommonExpr(t *testing.T) { expr: `(2 > 1) and (2 > 1)`, program: &vm.Program{ Bytecode: []vm.Opcode{ - vm.OpLoadCommon, - vm.OpJumpIfSaveCommon, - vm.OpPop, vm.OpPush, vm.OpPush, vm.OpLessOrEqual, @@ -169,7 +154,7 @@ func TestAnalyzeCommonExpr(t *testing.T) { vm.OpMore, vm.OpSaveCommon, }, - Arguments: []int{0, 5, 0, 0, 1, 0, 0, 8, 0, 0, 5, 0, 1, 0, 0, 0}, + Arguments: []int{0, 1, 0, 0, 8, 0, 0, 5, 0, 1, 0, 0, 0}, }, }, { @@ -239,11 +224,16 @@ func TestAnalyzeCommonExpr(t *testing.T) { Bytecode: []vm.Opcode{ vm.OpPush, vm.OpBuiltin, + vm.OpSaveCommon, + vm.OpLoadCommon, + vm.OpJumpIfSaveCommon, + vm.OpPop, vm.OpPush, vm.OpBuiltin, + vm.OpSaveCommon, vm.OpEqualInt, }, - Arguments: []int{0, 3, 0, 3, 0}, + Arguments: []int{0, 3, 0, 0, 4, 0, 0, 3, 0, 0}, }, }, { @@ -327,9 +317,6 @@ func TestAnalyzeCommonExpr(t *testing.T) { program: &vm.Program{ Constants: []interface{}{1.7, 4}, Bytecode: []vm.Opcode{ - vm.OpLoadCommon, - vm.OpJumpIfSaveCommon, - vm.OpPop, vm.OpPush, vm.OpPush, vm.OpAdd, @@ -355,12 +342,37 @@ func TestAnalyzeCommonExpr(t *testing.T) { vm.OpFalse, vm.OpEnd, }, - Arguments: []int{0, 5, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 1, 0, 0, 7, 0, 0, 0, 4, 0, 0, 8, 0, 0}, + Arguments: []int{0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 1, 0, 0, 7, 0, 0, 0, 4, 0, 0, 8, 0, 0}, + }, + }, + { + input: `(heavyFunc() + tinyFunc1()) + (heavyFunc() + tinyFunc2())`, + expr: "(heavyFunc() + tinyFunc1()) + (heavyFunc() + tinyFunc2())", + program: &vm.Program{ + Bytecode: []vm.Opcode{ + vm.OpCall0, + vm.OpSaveCommon, + vm.OpCall0, + vm.OpAdd, + vm.OpLoadCommon, + vm.OpJumpIfSaveCommon, + vm.OpPop, + vm.OpCall0, + vm.OpSaveCommon, + vm.OpCall0, + vm.OpAdd, + vm.OpAdd, + }, + Arguments: []int{0, 0, 1, 0, 0, 3, 0, 0, 0, 2, 0, 0}, }, }, } { t.Run(tt.input, func(t *testing.T) { - program, err := expr.Compile(tt.input, expr.Env(Env{}), expr.Optimize(false), expr.AllowReuseCommon(true)) + program, err := expr.Compile(tt.input, expr.Env(Env{}), + expr.Function("heavyFunc", func(...interface{}) (interface{}, error) { return nil, nil }), + expr.Function("tinyFunc1", func(...interface{}) (interface{}, error) { return nil, nil }), + expr.Function("tinyFunc2", func(...interface{}) (interface{}, error) { return nil, nil }), + expr.Optimize(false), expr.AllowReuseCommon(true)) if err != nil { assert.Nil(t, err) } else { diff --git a/compiler/compiler.go b/compiler/compiler.go index 26f748f02..85cfb0c8e 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -85,8 +85,9 @@ type compiler struct { } type exprRecord struct { - id int // sub-expr uniq id - cnt int // how many times of sub-expr repeated + id int // sub-expr uniq id + loc file.Location // first location of sub-expr + cnt int // how many times of sub-expr repeated } func (c *compiler) emitLocation(loc file.Location, op Opcode, arg int) int { @@ -324,13 +325,20 @@ func (c *compiler) UnaryNode(node *ast.UnaryNode) { } func (c *compiler) BinaryNode(node *ast.BinaryNode) { - if needReuseCommon, exprUniqId := c.needReuseCommon(node); needReuseCommon { - c.emit(OpLoadCommon, exprUniqId) - cEnd := c.emit(OpJumpIfSaveCommon, placeholder) - c.emit(OpPop) + // if first occur, the result must not be computed before + // otherwise, the result need to check save before reuse result of common + if needReuseCommon, isFirstOccur, exprUniqId := c.needReuseCommon(node); needReuseCommon { + var cEnd int + if !isFirstOccur { + c.emit(OpLoadCommon, exprUniqId) + cEnd = c.emit(OpJumpIfSaveCommon, placeholder) + c.emit(OpPop) + } defer func() { c.emit(OpSaveCommon, exprUniqId) - c.patchJump(cEnd) + if !isFirstOccur { + c.patchJump(cEnd) + } }() } @@ -566,13 +574,20 @@ func (c *compiler) SliceNode(node *ast.SliceNode) { } func (c *compiler) CallNode(node *ast.CallNode) { - if needReuseCommon, exprUniqId := c.needReuseCommon(node); needReuseCommon { - c.emit(OpLoadCommon, exprUniqId) - cEnd := c.emit(OpJumpIfSaveCommon, placeholder) - c.emit(OpPop) + // if first occur, the result must not be computed before + // otherwise, the result need to check save before reuse result of common + if needReuseCommon, isFirstOccur, exprUniqId := c.needReuseCommon(node); needReuseCommon { + var cEnd int + if !isFirstOccur { + c.emit(OpLoadCommon, exprUniqId) + cEnd = c.emit(OpJumpIfSaveCommon, placeholder) + c.emit(OpPop) + } defer func() { c.emit(OpSaveCommon, exprUniqId) - c.patchJump(cEnd) + if !isFirstOccur { + c.patchJump(cEnd) + } }() } From f84c5a98f555a187a861bcc94218d80d0fa2c7ed Mon Sep 17 00:00:00 2001 From: zhuliquan Date: Thu, 27 Jul 2023 01:47:50 +0800 Subject: [PATCH 11/11] feature: set first loc at set uniq id --- compiler/analysis_common.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/analysis_common.go b/compiler/analysis_common.go index e71066aa6..4b5d82ecf 100644 --- a/compiler/analysis_common.go +++ b/compiler/analysis_common.go @@ -341,7 +341,7 @@ func (c *compiler) countCommonExpr(subExpr string, loc file.Location) { } hash := fmt.Sprintf("%x", sha1.Sum([]byte(subExpr))) if cs, ok := c.exprRecords[hash]; !ok { - c.exprRecords[hash] = &exprRecord{cnt: 1, loc: loc, id: -1} + c.exprRecords[hash] = &exprRecord{cnt: 1, id: -1} } else { cs.cnt = cs.cnt + 1 } @@ -356,6 +356,7 @@ func (c *compiler) needReuseCommon(n ast.Node) (bool, bool, int) { if ok && cs.cnt > 1 { if cs.id == -1 { cs.id = c.commonExprInc + cs.loc = n.Location() c.commonExpr[cs.id] = expr c.commonExprInc += 1 }