Last active
October 29, 2015 23:06
-
-
Save iwatakeshi/d1973038c1417443749f to your computer and use it in GitHub Desktop.
An pseudo code for mr-doc.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
class Source { | |
constructor(source) { | |
source = source[source.length - 1] === this.EOF ? | |
source : source += this.EOF; | |
this._source = []; | |
for(var i = 0; i < source.length; i++) { this._source[this._source.length] = source[i]; } | |
this._line = 1; | |
this._position = 0; | |
this._column = 1; | |
} | |
/** | |
* Returns the source | |
* @return {Array} The source | |
*/ | |
get file () { | |
return this._source; | |
} | |
/** | |
* Sets the line number | |
* @param {Number} num The number to assign | |
*/ | |
set line (num) { | |
this._line = num; | |
} | |
/** | |
* Returns the current line number | |
* @return {Number} The current line number | |
*/ | |
get line () { | |
return this._line; | |
} | |
/** | |
* Sets the position number | |
* @param {Number} num The number to assign | |
*/ | |
set position (num) { | |
this._position = num; | |
} | |
/** | |
* Returns the current position | |
* @return {Number} The current position | |
*/ | |
get position () { | |
return this._position; | |
} | |
/** | |
* Sets the column number | |
* @param {Number} num The number to assign | |
*/ | |
set column (num) { | |
this._column = num; | |
} | |
/** | |
* Returns the current column | |
* @return {Number} The current column | |
*/ | |
get column () { | |
return this._column; | |
} | |
/** | |
* Returns the End of File character | |
*/ | |
get EOF () { | |
return '\0'; | |
} | |
toString () { | |
return `line: ${ this.line }, column: ${ this.column }, position: ${ this.position }`; | |
} | |
toJSON(){ | |
return { | |
"source": { | |
"line": this.line, | |
"column": this.column, | |
"position": this.position | |
} | |
}; | |
} | |
} | |
class Scanner extends Source { | |
constructor(source){ | |
super(source); | |
this._stack = []; | |
this._stringBuffer = ''; | |
this._isEOF = false; | |
} | |
set isEOF (truth) { | |
this._isEOF = truth; | |
} | |
get isEOF () { | |
return this._isEOF; | |
} | |
isWhiteSpace (char) { | |
return char === ' '; | |
} | |
scan (callback) { | |
this.ignoreWhiteSpace(); | |
while(this.peekChar() !== this.EOF) { | |
var token = this.nextToken(callback); | |
if(token) this._stack[this._stack.length] = token; | |
this.ignoreWhiteSpace(); | |
} | |
} | |
nextChar () { | |
// If we are at the end or over the length | |
// of the source then return EOF | |
if(this.position >= this.file.length) { | |
this.isEOF = true; | |
return this.EOF; | |
} | |
// If we reach a new line then | |
// increment the line and reset the column | |
// else increment the column | |
if(this.file[this.position] === '\n') { | |
this.line++; | |
this.column = 1; | |
} else this.column++; | |
return this.file[this.position++]; | |
} | |
peekChar (peek) { | |
// If we peek and the we reach the end or over | |
// the length then return EOF | |
if (this.position + peek >= this.file.length){ | |
this.isEOF = true; | |
return this.EOF; | |
} | |
return this.file[this.position + (peek ? peek : 0)]; | |
} | |
nextToken (callback) { | |
if(typeof callback === 'function'){ | |
var character = this.peekChar(); | |
switch(character) { | |
case '0': case '1': case '2': | |
case '3': case '4': case '5': | |
case '6': case '7': case '8': case '9': | |
return callback.apply(this, ['number', character]); | |
break; | |
default: | |
return callback.apply(this, ['default', character]); | |
break; | |
} | |
} | |
} | |
ignoreWhiteSpace () { | |
console.log('skipping whitespace'); | |
while(this.isWhiteSpace(this.peekChar())) { | |
this.nextChar(); | |
} | |
} | |
toStream () { | |
return this._stack; | |
} | |
} | |
class Token { | |
constructor (type, value, source) { | |
this._type = type; | |
this._value = value; | |
this._source = source; | |
} | |
get type () { | |
return this._type; | |
} | |
get value () { | |
return this._value; | |
} | |
get source () { | |
return this._source; | |
} | |
toJSON () { | |
return Object.assign(this._source, { | |
"token": { | |
"type": this.type, | |
"value": this.value | |
} | |
}); | |
} | |
} | |
var scanner = new Scanner("var greet = 'Hello world';\n var greet2 = 'This is cool!'"); | |
scanner.scan(function (type, char) { | |
switch(type) { | |
case 'number': | |
this.nextChar(); | |
return new Token(type, char, this.toJSON()); | |
break; | |
case 'default': | |
this.nextChar(); | |
return new Token('other', char, this.toJSON()); | |
break; | |
} | |
}); | |
scanner.toStream().forEach(token => console.log(token ? token.toJSON() : '')); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment