Commit 2f8ec932 authored by Pouya Kary's avatar Pouya Kary

half of migration

parent 2a5d19fd
......@@ -76,7 +76,13 @@
"EEEEEE",
"goog",
"scrollbars",
"onoutclick"
"javascripts",
"onmouseover",
"onmouseleave",
"SVGA",
"regulex's",
"Unicodify",
"genkit"
],
// flagWords - list of words to be always considered incorrect
// This is useful for offensive words and common spelling errors.
......
//
// Copyright 2016 Kary Foundation, Inc.
// Author: Pouya Kary <k@karyfoundation.org>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
//
// This level is like a preprocessor on the regulex's AST. for handling
// the lookahead problem.
//
//
// ─── MAIN ───────────────────────────────────────────────────────────────────────
//
export function fixLookahead ( ast: blueprints.regulex.IRegExAST ):
blueprints.regulex.IRegExAST {
let topNode : blueprints.regulex.IBaseNode
let bottomNode : blueprints.regulex.INodeLookahead
for ( let counter = 0; counter < ast.tree.length - 1; counter++ ) {
topNode = ast.tree[ counter ]
bottomNode = <blueprints.regulex.INodeLookahead> ast.tree[ counter + 1 ]
if ( bottomNode.type === 'assert' ) {
if ( bottomNode.assertionType === 'AssertLookahead' ||
bottomNode.assertionType === 'AssertNegativeLookahead' ) {
bottomNode.type = 'lookahead'
bottomNode.statement = Object.assign({ }, topNode )
bottomNode.status = (
bottomNode.assertionType === 'AssertLookahead' )
ast.tree[ counter ] = null
counter++;
}}}
return ast
}
// ────────────────────────────────────────────────────────────────────────────────
//
// Copyright 2016 Kary Foundation, Inc.
// Author: Pouya Kary <k@karyfoundation.org>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
//
// ─── IMPORTS ────────────────────────────────────────────────────────────────────
//
// tools
import * as repeats from '../generators/nodes/repeats';
// nodes
import * as exactNode from '../generators/nodes/exact'
import * as charsetNode from '../generators/nodes/charset'
import * as groupNode from '../generators/nodes/group'
import * as choiceNode from '../generators/nodes/choice'
import * as lookaheadNode from '../generators/nodes/lookahead'
import * as assertNode from '../generators/nodes/assert'
import * as dotNode from '../generators/nodes/dot'
//
// ─── EXPORTS ────────────────────────────────────────────────────────────────────
//
/** Compiles _Regulex AST_ into _Concerto AST_ */
export function compile ( tree: blueprints.regulex.IBaseNode[ ] ) {
let ast = new Array<blueprints.block.IBlock> ( )
for ( let node of tree ) {
if ( node !== null ) {
let intermediateNode = handleOneNode( node )
if ( intermediateNode.type === 'block' )
ast.push( intermediateNode.value[ 0 ] )
else
for ( let child of intermediateNode.value )
ast.push( child )
}}
return ast
}
//
// ─── HANDLE ONE NODE ────────────────────────────────────────────────────────────
//
function handleOneNode ( node: blueprints.regulex.IBaseNode ):
blueprints.block.IIntermediateNode {
// firs we handle the block
let intermediateNode
switch ( node.type ) {
case 'exact':
intermediateNode =
exactNode.generate( <blueprints.regulex.INodeExact> node )
break
case 'charset':
intermediateNode =
charsetNode.generate( <blueprints.regulex.INodeSet> node )
break
case 'group':
intermediateNode =
groupNode.generate( <blueprints.regulex.INodeGroup> node )
break
case 'choice':
intermediateNode =
choiceNode.generate( <blueprints.regulex.INodeChoice> node )
break
case 'dot':
intermediateNode =
dotNode.generate( node )
break
case 'lookahead':
intermediateNode =
lookaheadNode.generate( <blueprints.regulex.INodeLookahead> node )
break
case 'assert':
intermediateNode =
assertNode.generate( <blueprints.regulex.INodeAssert> node )
break
}
// then we handle the repeat of the block
return repeats.generate( intermediateNode )
}
// ────────────────────────────────────────────────────────────────────────────────
//
// Copyright 2016 Kary Foundation, Inc.
// Author: Pouya Kary <k@karyfoundation.org>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
//
// ─── STARTING ADDER ─────────────────────────────────────────────────────────────
//
export function compile ( concertoAST: blueprints.block.IBlock[ ] ):
blueprints.recarr.INode {
if ( concertoAST.length === 0 ) return null
let firstIndex = concertoAST[ 0 ]
let children = new Array<blueprints.recarr.IStatement> ( )
// is there any children?
if ( firstIndex.children !== undefined && firstIndex.children !== null )
for ( let statement of firstIndex.children )
children.push({
name: statement.name,
block: compile( statement.children )
})
// then it's time to return the new node
if ( concertoAST.length === 1 )
return {
type: firstIndex.type,
fields: firstIndex.fields,
statements: children
}
else
return {
type: firstIndex.type,
fields: firstIndex.fields,
statements: children,
next: compile( concertoAST.splice( 1 ) )
}
}
// ────────────────────────────────────────────────────────────────────────────────
//
// Copyright 2016 Kary Foundation, Inc.
// Author: Pouya Kary <k@karyfoundation.org>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
//
// ─── MAIN ───────────────────────────────────────────────────────────────────────
//
export function compile ( block: blueprints.recarr.INode ) {
return `<xml xmlns="http://www.w3.org/1999/xhtml"><block type="compose" id="composer" deletable="false" x="40" y="40"><statement name="blocks">${ generateBlockXML( block ) }</statement></block></xml>`
}
//
// ─── GENERATE XML FOR BLOCK ─────────────────────────────────────────────────────
//
function generateBlockXML ( block: blueprints.recarr.INode ): string {
let result = [ `<block type="${ block.type }" id="${ generateId( ) }">` ];
// adding fields:
if ( block.fields !== undefined && block.fields !== null )
for ( let field of block.fields )
result.push( `<field name="${ field.name }">${ field.value }</field>` )
// adding statements
if ( block.statements !== undefined )
for ( let statement of block.statements )
result.push( `<statement name="${ statement.name }">${ generateBlockXML( statement.block ) }</statement>`)
// adding the next block
if ( block.next !== null && block.next !== undefined )
result.push( `<next>${ generateBlockXML( block.next ) }</next>`)
// done
result.push('</block>')
return result.join('')
}
//
// ─── RANDOM ID GENERATOR ────────────────────────────────────────────────────────
//
function generateId ( ): string {
let result = ''
function generateRandomChar ( ): string {
let n = Math.floor( Math.random( ) * 62 )
if ( n < 10 ) return n.toString( )
if ( n < 36 ) return String.fromCharCode( n + 55 )
return String.fromCharCode( n + 61 )
}
while ( result.length < 20 ) result += generateRandomChar( )
return result
}
// ────────────────────────────────────────────────────────────────────────────────
//
// Copyright 2016 Kary Foundation, Inc.
// Author: Pouya Kary <k@karyfoundation.org>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
//
// ─── STATEMENT GENERATOR ────────────────────────────────────────────────────────
//
export function generateStatement ( blocks: blueprints.block.IBlock[ ],
name = 'blocks' ):
blueprints.block.IStatement {
return {
name: name,
children: blocks
}
}
//
// ─── TEXT ENCODER ───────────────────────────────────────────────────────────────
//
export function encodeText ( text: string ): string {
let result = [ ]
for ( let char of text ) {
switch ( char ) {
case '<':
result.push( '&lt;' )
break
case '>':
result.push( '&gt;' )
break
case '/':
result.push( '\\/' )
break
case '&':
result.push( '&amp;' )
default:
result.push( char )
}
}
return result.join('')
}
// ────────────────────────────────────────────────────────────────────────────────
//
// Copyright 2016 Kary Foundation, Inc.
// Author: Pouya Kary <k@karyfoundation.org>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
//
// ─── IMPORTS ────────────────────────────────────────────────────────────────────
//
import * as genkit from '../genkit'
//
// ─── EXPORT ─────────────────────────────────────────────────────────────────────
//
export function generate ( node: blueprints.regulex.INodeSet ):
blueprints.block.IIntermediateNode {
return {
type: 'block',
node: node,
value: [
switchForSetGenerator( node )
]}}
//
// ─── GENERATOR ──────────────────────────────────────────────────────────────────
//
function switchForSetGenerator ( node: blueprints.regulex.INodeSet ):
blueprints.block.IBlock {
// Simple Range
if ( node.ranges.length === 1 && node.chars === '' &&
node.exclude !== true && node.classes.length === 0 )
return composeRangeBlock( node.ranges[ 0 ] , 'range' )
// Special Character
if ( node.ranges.length === 0 && node.chars === '' &&
node.exclude !== true && node.classes.length === 1 )
return composeSpecialCharacterBlock( node )
// Check if simple set
let simpleSet = true
if ( node.ranges !== undefined )
for ( let range of node.ranges )
if ( !( range === 'az' || range === 'AZ' || range === '09' ) )
simpleSet = false
// composing for simple set
if ( simpleSet && node.classes.length === 0 ) return composeSimpleAlphabetBlock( node )
// composing for advanced set
return composeAdvancedSet( node )
}
//
// ─── RANGE SET BUILDER ──────────────────────────────────────────────────────────
//
function composeRangeBlock ( range: string, kind: string ): blueprints.block.IBlock {
return {
type: kind,
fields: [
{ name: 'start', value: genkit.encodeText( range[ 0 ] ) },
{ name: 'end', value: genkit.encodeText( range[ 1 ] ) }
]}}
//
// ─── SPECIAL CHARACTER ──────────────────────────────────────────────────────────
//
function composeSpecialCharacterBlock ( node: blueprints.regulex.INodeSet ):
blueprints.block.IBlock {
let quartetBlocksForClasses = {
'w': 'word',
'W': 'anything_but_word',
'd': 'digit',
'D': 'anything_but_digit',
's': 'whitespace',
'S': 'anything_but_whitespace',
'b': 'boundary',
'B': 'anything_but_boundary'
}
let block = quartetBlocksForClasses[ node.classes[ 0 ] ]
if ( block !== undefined )
return { type: block }
else
return {
type: 'free_form_regex',
fields: [{
name: 'regex', value: `\\\\${ node.classes[ 0 ] }`
}]}}
//
// ─── SIMPLE ALPHABET BLOCK ──────────────────────────────────────────────────────
//
function composeSimpleAlphabetBlock ( node: blueprints.regulex.INodeSet ):
blueprints.block.IBlock {
// fill ranges fields
let sets = {
numbers: 'FALSE',
lowercase: 'FALSE',
uppercase: 'FALSE',
}
if ( node.ranges !== undefined )
for ( let range of node.ranges )
switch ( range ) {
case '09':
sets.numbers = 'TRUE'
break
case 'az':
sets.lowercase = 'TRUE'
break
case 'AZ':
sets.uppercase = 'TRUE'
break
}
// composing final stuff:
return {
type: ( node.exclude )? 'anything_but': 'alphabet',
fields:[
{ name: 'numbers' , value: sets.numbers },
{ name: 'lowercase' , value: sets.lowercase },
{ name: 'uppercase' , value: sets.uppercase },
{ name: 'other' , value: genkit.encodeText( node.chars ) },
]}}
//
// ─── ADVANCE SET ────────────────────────────────────────────────────────────────
//
function composeAdvancedSet ( node: blueprints.regulex.INodeSet ):
blueprints.block.IBlock {
let children = new Array<blueprints.block.IBlock>( );
// adding ranges
for ( let range of node.ranges )
children.push( composeRangeBlock( range, 'sigma_range' ) )
// adding other chars
if ( node.chars !== '' && node.chars !== undefined )
children.push({
type: 'sigma_chars',
fields: [{
name: 'text', value: genkit.encodeText( node.chars )
}]})
// adding special characters
if ( node.classes.length > 0 ) {
children.push({
type: 'sigma_wildcard',
fields: [{
name: 'escapes', value: node.classes.map( c => `\\\\${ c }` ).join('')
}]})}
// returning...
return {
type: ( node.exclude )? 'exclude': 'sigma',
children: [
genkit.generateStatement( children )
]}}
// ────────────────────────────────────────────────────────────────────────────────
//
// Copyright 2016 Kary Foundation, Inc.
// Author: Pouya Kary <k@karyfoundation.org>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
//
// ─── IMPORTS ────────────────────────────────────────────────────────────────────
//
import * as compiler from '../../compilers/level1'
//
// ─── GENERATOR ──────────────────────────────────────────────────────────────────
//
export function generate ( node: blueprints.regulex.INodeLookahead ):
blueprints.block.IIntermediateNode {
return {
type: 'block',
node: node,
value: [{
type: 'lookahead',
children: [
{
name: 'blocks',
children: compiler.compile([ node.statement ])
},
{
name: 'lookahead',
children: compiler.compile( node.sub )
}
],
fields: [{
name: 'status',
value: ( node.status )? 'positive' : 'negative'
}]}]}}
// ────────────────────────────────────────────────────────────────────────────────
//
// Copyright 2016 Kary Foundation, Inc.
// Author: Pouya Kary <k@karyfoundation.org>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
//
// ─── IMPORTS ────────────────────────────────────────────────────────────────────
//
import * as genkit from '../genkit'
//
// ─── GENERATORS ─────────────────────────────────────────────────────────────────
//
export function generate ( intermediateNode: blueprints.block.IIntermediateNode ):
blueprints.block.IIntermediateNode {
// No Repeat
if ( intermediateNode.node.repeat === undefined ) return intermediateNode
let min = intermediateNode.node.repeat.min
let max = intermediateNode.node.repeat.max
let blocks = intermediateNode.value
let result : blueprints.block.IBlock[ ]
// Maybe block
if ( min === 0 && max === 1 )
result = composeStaticRepeat( 'maybe', blocks )
// One or More
else if ( min === 1 && max === Infinity )
result = composeStaticRepeat( 'one_or_more', blocks )
// Any number of
else if ( min === 0 && max === Infinity )
result = composeStaticRepeat( 'any_number_of', blocks )
// Exact Repeat
else if ( min === max )
result = composeExactRepeat( min, blocks )
// At least repeat
else if ( max === Infinity )
result = composeAtLeastRepeat( min, blocks )
// Range Repeat
else result = composeRangeRepeat( min, max, blocks )
// done
intermediateNode.value = result
return intermediateNode
}
//
// ─── COMPOSE MAYBE REPEAT ───────────────────────────────────────────────────────
//
function composeStaticRepeat ( repeatType: string,
blocks: blueprints.block.IBlock[ ] ):
blueprints.block.IBlock[ ] {
return [{
type: repeatType,
children: [
genkit.generateStatement( blocks )
]}]}
//
// ─── COMPOSE REPEAT TIMES ───────────────────────────────────────────────────────
//
function composeExactRepeat ( count: number,
blocks: blueprints.block.IBlock[ ] ):
blueprints.block.IBlock[ ] {
return [{
type: 'repeat',
fields: [{
name: 'count',
value: count.toString( )
}],
children: [
genkit.generateStatement( blocks )
]}]}
//
// ─── COMPOSE AT LEAST REPEAT ────────────────────────────────────────────────────
//
function composeAtLeastRepeat ( min: number,
blocks: blueprints.block.IBlock[ ] ):
blueprints.block.IBlock[ ] {
return [{
type: 'repeat_at_least',
fields: [{
name: 'count',
value: min.toString( )
}],
children: [
genkit.generateStatement( blocks )
]}]}
//
// ─── COMPOSE REPEAT IN RANGE ────────────────────────────────────────────────────
//
function composeRangeRepeat ( min: number,
max: number,
blocks: blueprints.block.IBlock[ ] ):
blueprints.block.IBlock[ ] {
return [{
type: 'repeat_in_range',
fields: [
{ name: 'start', value: min.toString( ) },
{ name: 'end', value: max.toString( ) },
],
children: [
genkit.generateStatement( blocks )
]}]}
// ────────────────────────────────────────────────────────────────────────────────
\ No newline at end of file
//
// Copyright 2016 Kary Foundation, Inc.
// Author: Pouya Kary <k@karyfoundation.org>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
//
// ─── IMPORTS ────────────────────────────────────────────────────────────────────
//
import * as preprocessor from './compilers/level0'