initial ideas
This commit is contained in:
		
							
								
								
									
										54
									
								
								lang2/lexer.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								lang2/lexer.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | ||||
| type Token<T extends string> = { | ||||
| 	type: T, | ||||
| 	string: string, | ||||
| } | ||||
|  | ||||
| type LexerProps<T extends string> = { | ||||
| 	rules: { | ||||
| 		[key in T]: RegExp; | ||||
| 	}, | ||||
| 	// postprocess?: (token: Token<T>) => | ||||
| } | ||||
|  | ||||
| const entries = <K extends string, V>(obj: {[key in K]: V}) => { | ||||
| 	return Object.entries(obj) as Array<[K, V]>; | ||||
| } | ||||
|  | ||||
| const lexer = <T extends string>(props: LexerProps<T>) => { | ||||
| 	const {rules} = props; | ||||
| 	return (string: string): Array<Token<T>> => { | ||||
| 		const tokens: Array<Token<T>> = []; | ||||
| 		let str = string; | ||||
| 		while (str.length) { | ||||
| 			let matched = false; | ||||
| 			for (const [type, matcher] of entries(rules)) { | ||||
| 				const match = str.match(matcher); | ||||
| 				if (match && match.index === 0) { | ||||
| 					if (type !== "_skip") { | ||||
| 						tokens.push({type, string: match[0]}); | ||||
| 					} | ||||
| 					str = str.slice(match[0].length); | ||||
| 					matched = true; | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
| 			if (!matched) { | ||||
| 				console.log(tokens); | ||||
| 				console.log(str); | ||||
| 				throw 'Infinite Loop'; | ||||
| 			} | ||||
| 		} | ||||
| 		return tokens; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| const my_lexer = lexer({ | ||||
| 	rules: { | ||||
| 		symbol: /\w+/, | ||||
| 		punctuation: /[\.,:;()[\]{}]/, | ||||
| 		string_literal: /"([^"\\]|\\.)*"/, | ||||
| 		_skip: /\s+/, | ||||
| 	} | ||||
| }); | ||||
|  | ||||
| console.log(my_lexer(`abc def { ghi } "string literal!" "with \\"escaped\\" quote marks"`)); | ||||
							
								
								
									
										28
									
								
								lang2/peg.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								lang2/peg.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| const Expression = rule( | ||||
| 	[{head: Term}, {tail: star([_, slash("+", "-"), _, Term])}], | ||||
| 	({head, tail}) => { | ||||
| 		return tail.reduce(function(result, element) { | ||||
| 			if (element[1] === "+") { return result + element[3]; } | ||||
| 			if (element[1] === "-") { return result - element[3]; } | ||||
| 		}, head); | ||||
| 	} | ||||
| ); | ||||
|  | ||||
| const Term = rule( | ||||
| 	[{head: Factor}, {tail: star([_, slash("*", "/"), _, Factor])}], | ||||
| 	({head, tail}) => { | ||||
| 		return tail.reduce(function(result, element) { | ||||
| 			if (element[1] === "*") { return result * element[3]; } | ||||
| 			if (element[1] === "/") { return result / element[3]; } | ||||
| 		}, head); | ||||
| 	} | ||||
| ); | ||||
|  | ||||
| const Factor = slash( | ||||
| 	rule(["(", _, {expr: Expression}, _, ")"], ({expr}) => expr), | ||||
| 	Integer | ||||
| ); | ||||
|  | ||||
| const Integer = rule([_, /[0-9]+/], () => { return parseInt(text(), 10); }); | ||||
|  | ||||
| const _ = /[ \t\n\r]*/; | ||||
		Reference in New Issue
	
	Block a user
	 dylan
					dylan