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/analysis_common.go b/compiler/analysis_common.go new file mode 100644 index 000000000..4b5d82ecf --- /dev/null +++ b/compiler/analysis_common.go @@ -0,0 +1,369 @@ +package compiler + +import ( + "crypto/sha1" + "fmt" + "sort" + "strconv" + "strings" + + "github.com/antonmedv/expr/ast" + "github.com/antonmedv/expr/file" +) + +func (c *compiler) analyzeCommonExpr(node ast.Node) { + switch n := node.(type) { + case *ast.NilNode: + c.analyzeCommonNilNode(n) + case *ast.IdentifierNode: + c.analyzeCommonIdentifierNode(n) + case *ast.IntegerNode: + c.analyzeCommonIntegerNode(n) + case *ast.FloatNode: + c.analyzeCommonFloatNode(n) + case *ast.BoolNode: + c.analyzeCommonBoolNode(n) + case *ast.StringNode: + c.analyzeCommonStringNode(n) + case *ast.ConstantNode: + c.analyzeCommonConstantNode(n) + case *ast.UnaryNode: + c.analyzeCommonUnaryNode(n) + case *ast.BinaryNode: + c.analyzeCommonBinaryNode(n) + case *ast.ChainNode: + c.analyzeCommonChainNode(n) + case *ast.MemberNode: + c.analyzeCommonMemberNode(n) + case *ast.SliceNode: + c.analyzeCommonSliceNode(n) + case *ast.CallNode: + c.checkCallNode(n) + case *ast.BuiltinNode: + c.analyzeCommonBuiltinNode(n) + case *ast.ClosureNode: + c.analyzeCommonClosureNode(n) + case *ast.PointerNode: + c.analyzeCommonPointerNode(n) + case *ast.ConditionalNode: + c.analyzeCommonConditionalNode(n) + case *ast.ArrayNode: + c.analyzeCommonArrayNode(n) + case *ast.MapNode: + c.analyzeCommonMapNode(n) + case *ast.PairNode: + // do nothing + default: + panic(fmt.Sprintf("undefined node type (%T)", node)) + } +} + +func (c *compiler) analyzeCommonNilNode(n *ast.NilNode) { + n.SetSubExpr("nil") +} + +func (c *compiler) analyzeCommonIdentifierNode(n *ast.IdentifierNode) { + n.SetSubExpr(n.Value) +} + +func (c *compiler) analyzeCommonIntegerNode(n *ast.IntegerNode) { + n.SetSubExpr(strconv.FormatInt(int64(n.Value), 10)) +} + +func (c *compiler) analyzeCommonFloatNode(n *ast.FloatNode) { + n.SetSubExpr(strconv.FormatFloat(n.Value, 'f', 10, 64)) +} + +func (c *compiler) analyzeCommonBoolNode(n *ast.BoolNode) { + n.SetSubExpr(strconv.FormatBool(n.Value)) +} + +func (c *compiler) analyzeCommonStringNode(n *ast.StringNode) { + n.SetSubExpr(strconv.Quote(n.Value)) +} + +func (c *compiler) analyzeCommonConstantNode(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) analyzeCommonUnaryNode(n *ast.UnaryNode) { + c.analyzeCommonExpr(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) analyzeCommonBinaryNode(n *ast.BinaryNode) { + c.analyzeCommonExpr(n.Left) + c.analyzeCommonExpr(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.countCommonExpr(n.SubExpr(), n.Location()) + } +} + +func (c *compiler) analyzeCommonChainNode(n *ast.ChainNode) { + c.analyzeCommonExpr(n.Node) + n.SetSubExpr(n.Node.SubExpr()) +} + +func (c *compiler) analyzeCommonMemberNode(n *ast.MemberNode) { + c.analyzeCommonExpr(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.analyzeCommonExpr(n.Property) + buf.WriteString("[") + buf.WriteString(n.Property.SubExpr()) + buf.WriteString("]") + } + } + n.SetSubExpr(buf.String()) +} + +func (c *compiler) analyzeCommonSliceNode(n *ast.SliceNode) { + buf := strings.Builder{} + c.analyzeCommonExpr(n.Node) + buf.WriteString(n.Node.SubExpr()) + buf.WriteString("[") + toStr := "" + fromStr := "" + if n.To != nil { + c.analyzeCommonExpr(n.To) + toStr = n.To.SubExpr() + } + if n.From != nil { + c.analyzeCommonExpr(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) { + buf := strings.Builder{} + c.analyzeCommonExpr(n.Callee) + buf.WriteString(n.Callee.SubExpr()) + buf.WriteString("(") + for i, arg := range n.Arguments { + c.analyzeCommonExpr(arg) + if i != 0 { + buf.WriteString(",") + } + buf.WriteString(arg.SubExpr()) + } + buf.WriteString(")") + n.SetSubExpr(buf.String()) + c.countCommonExpr(n.SubExpr(), n.Location()) +} + +func (c *compiler) analyzeCommonBuiltinNode(n *ast.BuiltinNode) { + buf := strings.Builder{} + buf.WriteString(n.Name) + buf.WriteString("(") + for i, arg := range n.Arguments { + c.analyzeCommonExpr(arg) + if i != 0 { + buf.WriteString(",") + } + buf.WriteString(arg.SubExpr()) + } + buf.WriteString(")") + n.SetSubExpr(buf.String()) +} + +func (c *compiler) analyzeCommonClosureNode(n *ast.ClosureNode) { + c.analyzeCommonExpr(n.Node) + // omit '{' / '}' + n.SetSubExpr(n.Node.SubExpr()) +} + +func (c *compiler) analyzeCommonPointerNode(n *ast.PointerNode) { + // do nothing + n.SetSubExpr("#") +} + +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(" ? ") + buf.WriteString(n.Exp1.SubExpr()) + buf.WriteString(" : ") + buf.WriteString(n.Exp2.SubExpr()) + n.SetSubExpr(buf.String()) +} + +func (c *compiler) analyzeCommonArrayNode(n *ast.ArrayNode) { + buf := strings.Builder{} + buf.WriteString("[") + for i, node := range n.Nodes { + c.analyzeCommonExpr(node) + if i != 0 { + buf.WriteString(",") + } + buf.WriteString(node.SubExpr()) + } + buf.WriteString("]") + n.SetSubExpr(buf.String()) +} + +func (c *compiler) analyzeCommonMapNode(n *ast.MapNode) { + pairs := make([]*ast.PairNode, 0) + for i := range n.Pairs { + pair := n.Pairs[i].(*ast.PairNode) + c.analyzeCommonExpr(pair.Key) + c.analyzeCommonExpr(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) countCommonExpr(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, id: -1} + } else { + cs.cnt = cs.cnt + 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))) + cs, ok := c.exprRecords[hash] + 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 + } + needReuseCommon = true + isFirstOccur = n.Location().Line == cs.loc.Line && n.Location().Column == cs.loc.Column + exprUniqId = cs.id + } + } + return needReuseCommon, isFirstOccur, exprUniqId +} diff --git a/compiler/analysis_common_test.go b/compiler/analysis_common_test.go new file mode 100644 index 000000000..0a0c69b8d --- /dev/null +++ b/compiler/analysis_common_test.go @@ -0,0 +1,387 @@ +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.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, 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.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, 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.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, 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.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, 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.OpSaveCommon, + vm.OpLoadCommon, + vm.OpJumpIfSaveCommon, + vm.OpPop, + vm.OpPush, + vm.OpBuiltin, + vm.OpSaveCommon, + vm.OpEqualInt, + }, + Arguments: []int{0, 3, 0, 0, 4, 0, 0, 3, 0, 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.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, 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.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 { + 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 423dd6217..85cfb0c8e 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -32,6 +32,15 @@ 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.analyzeCommonExpr(tree.Node) + defer func() { + program.CommonExpr = c.commonExpr + }() + } } c.compile(tree.Node) @@ -69,6 +78,16 @@ 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 + 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 { @@ -289,7 +308,6 @@ func (c *compiler) ConstantNode(node *ast.ConstantNode) { func (c *compiler) UnaryNode(node *ast.UnaryNode) { c.compile(node.Node) - switch node.Operator { case "!", "not": @@ -307,9 +325,25 @@ func (c *compiler) UnaryNode(node *ast.UnaryNode) { } func (c *compiler) BinaryNode(node *ast.BinaryNode) { + // 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) + if !isFirstOccur { + c.patchJump(cEnd) + } + }() + } + l := kind(node.Left) r := kind(node.Right) - switch node.Operator { case "==": c.compile(node.Left) @@ -326,7 +360,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", "||": @@ -534,6 +574,23 @@ func (c *compiler) SliceNode(node *ast.SliceNode) { } func (c *compiler) CallNode(node *ast.CallNode) { + // 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) + if !isFirstOccur { + 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/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 diff --git a/vm/opcodes.go b/vm/opcodes.go index 4bc9abf4d..cb61d29bb 100644 --- a/vm/opcodes.go +++ b/vm/opcodes.go @@ -29,6 +29,7 @@ const ( OpJumpIfFalse OpJumpIfNil OpJumpIfNotNil + OpJumpIfSaveCommon // if common value save skip common calculate OpJumpIfEnd OpJumpBackward OpIn @@ -68,6 +69,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 936eca9a2..542d13f13 100644 --- a/vm/program.go +++ b/vm/program.go @@ -15,13 +15,14 @@ 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 } func (program *Program) Disassemble() string { @@ -46,6 +47,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) { @@ -151,6 +155,9 @@ func (program *Program) Disassemble() string { case OpJumpIfNotNil: jump("OpJumpIfNotNil") + case OpJumpIfSaveCommon: + jump("OpJumpIfSaveCommon") + case OpJumpIfEnd: jump("OpJumpIfEnd") @@ -269,6 +276,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 ec22c251d..9b96b03ac 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,18 @@ 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 { vm.scopes = vm.scopes[0:0] } - + commonCache := make([]interface{}, len(program.CommonExpr)) + for i := 0; i < len(commonCache); i++ { + commonCache[i] = _notSave + } vm.memoryBudget = MemoryBudget vm.memory = 0 vm.ip = 0 @@ -90,7 +96,6 @@ 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 OpInvalid: @@ -143,12 +148,12 @@ func (vm *VM) Run(program *Program, env interface{}) (_ interface{}, err error) vm.push(nil) case OpNegate: - v := runtime.Negate(vm.pop()) - vm.push(v) + a := vm.pop() + vm.push(runtime.Negate(a)) case OpNot: - v := vm.pop().(bool) - vm.push(!v) + a := vm.pop().(bool) + vm.push(!a) case OpEqual: b := vm.pop() @@ -188,6 +193,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 { @@ -445,6 +455,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: + commonCache[arg] = vm.current() + + case OpLoadCommon: + vm.push(commonCache[arg]) + case OpBegin: a := vm.pop() array := reflect.ValueOf(a)