changeset 1705:a6e27c8e7ef4

bbcode now returns data
author Franklin Schmidt <fschmidt@gmail.com>
date Sun, 03 Jul 2022 21:59:38 -0600
parents 19df8abc9805
children 93b9fd13a06c
files src/goodjava/bbcode/BBCode.java src/luan/modules/Parsers.luan src/luan/modules/parsers/BBCodeLuan.java
diffstat 3 files changed, 130 insertions(+), 152 deletions(-) [+]
line wrap: on
line diff
--- a/src/goodjava/bbcode/BBCode.java	Fri Jul 01 15:53:03 2022 -0600
+++ b/src/goodjava/bbcode/BBCode.java	Sun Jul 03 21:59:38 2022 -0600
@@ -2,6 +2,8 @@
 
 import java.util.List;
 import java.util.ArrayList;
+import java.util.Map;
+import java.util.LinkedHashMap;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import goodjava.parser.Parser;
@@ -9,59 +11,65 @@
 
 public final class BBCode {
 
-	public enum Target { HTML, TEXT }
+	public final class Element {
+		public final String name;
+		public final String param;
+		public final Object contents;  // String, Element, or List
+		public final Map<String,String> extra;
+
+		private Element(String name,Object contents) {
+			this(name,null,contents);
+		}
 
-	public interface Quoter {
-		public String quote(Target target,String text,String param);
+		private Element(String name,String param,Object contents) {
+			this(name,param,contents,null);
+		}
+
+		private Element(String name,String param,Object contents,Map<String,String> extra) {
+			this.name = name.toLowerCase();
+			this.param = param;
+			this.contents = contents;
+			this.extra = extra;
+		}
 	}
 
-	public static final Quoter defaultQuoter = new Quoter() {
-		public String quote(Target target,String text,String param) {
-			StringBuilder sb = new StringBuilder();
-			sb.append( "<blockquote>" );
-			if( param != null ) {
-				sb.append( htmlEncode(param) );
-				sb.append( " wrote:\n" );
-			}
-			sb.append( text );
-			sb.append( "</blockquote>" );
-			return sb.toString();
-		}
-	};
+	public static Object parse(String text) {
+		if( text.indexOf('[') == -1 )
+			return text;
+		return new BBCode(text).parse();
+	}
 
-	public Target target = Target.HTML;
-	public Quoter quoter = defaultQuoter;
 	private final Parser parser;
 
-	public BBCode(String text) {
+	private BBCode(String text) {
 		this.parser = new Parser(text);
 	}
 
-	public String parse() {
-		StringBuilder sb = new StringBuilder();
+	private Object parse() {
+		List list = new ArrayList();
 		StringBuilder text = new StringBuilder();
 		while( !parser.endOfInput() ) {
-			String block = parseBlock();
+			Element block = parseBlock();
 			if( block != null ) {
-				sb.append( textToString(text) );
-				sb.append(block);
+				add(list,text);
+				list.add( block );
 			} else {
 				text.append( parser.currentChar() );
 				parser.anyChar();
 			}
 		}
-		sb.append( textToString(text) );
-		return sb.toString();
+		add(list,text);
+		return list.size()==1 ? list.get(0) : list;
 	}
 
-	private String parseWellFormed() {
-		StringBuilder sb = new StringBuilder();
+	private Object parseWellFormed() {
+		List list = new ArrayList();
 		StringBuilder text = new StringBuilder();
 		while( !parser.endOfInput() ) {
-			String block = parseBlock();
+			Element block = parseBlock();
 			if( block != null ) {
-				sb.append( textToString(text) );
-				sb.append(block);
+				add(list,text);
+				list.add( block );
 				continue;
 			}
 			if( couldBeTag() )
@@ -69,16 +77,15 @@
 			text.append( parser.currentChar() );
 			parser.anyChar();
 		}
-		sb.append( textToString(text) );
-		return sb.toString();
+		add(list,text);
+		return list.size()==1 ? list.get(0) : list;
 	}
 
-	private String textToString(StringBuilder text) {
-		String s = text.toString();
-		text.setLength(0);
-		if( target == Target.HTML )
-			s = htmlEncode(s);
-		return s;
+	private void add(List list,StringBuilder text) {
+		if( text.length() > 0 ) {
+			list.add( text.toString() );
+			text.setLength(0);
+		}
 	}
 
 	private boolean couldBeTag() {
@@ -109,10 +116,10 @@
 		;
 	}
 
-	private String parseBlock() {
+	private Element parseBlock() {
 		if( parser.currentChar() != '[' )
 			return null;
-		String s;
+		Element s;
 		s = parseB();  if(s!=null) return s;
 		s = parseI();  if(s!=null) return s;
 		s = parseU();  if(s!=null) return s;
@@ -128,61 +135,61 @@
 		return null;
 	}
 
-	private String parseB() {
+	private Element parseB() {
 		parser.begin();
 		if( !parser.matchIgnoreCase("[b]") )
 			return parser.failure(null);
-		String content = parseWellFormed();
+		Object content = parseWellFormed();
 		if( !parser.matchIgnoreCase("[/b]") )
 			return parser.failure(null);
-		String rtn = target==Target.HTML ? "<b>"+content+"</b>" : content;
+		Element rtn = new Element("b",content);
 		return parser.success(rtn);
 	}
 
-	private String parseI() {
+	private Element parseI() {
 		parser.begin();
 		if( !parser.matchIgnoreCase("[i]") )
 			return parser.failure(null);
-		String content = parseWellFormed();
+		Object content = parseWellFormed();
 		if( !parser.matchIgnoreCase("[/i]") )
 			return parser.failure(null);
-		String rtn = target==Target.HTML ? "<i>"+content+"</i>" : content;
+		Element rtn = new Element("i",content);
 		return parser.success(rtn);
 	}
 
-	private String parseU() {
+	private Element parseU() {
 		parser.begin();
 		if( !parser.matchIgnoreCase("[u]") )
 			return parser.failure(null);
-		String content = parseWellFormed();
+		Object content = parseWellFormed();
 		if( !parser.matchIgnoreCase("[/u]") )
 			return parser.failure(null);
-		String rtn = target==Target.HTML ? "<u>"+content+"</u>" : content;
+		Element rtn = new Element("u",content);
 		return parser.success(rtn);
 	}
 
-	private String parseUrl1() {
+	private Element parseUrl1() {
 		parser.begin();
 		if( !parser.matchIgnoreCase("[url]") )
 			return parser.failure(null);
 		String url = parseRealUrl();
 		if( !parser.matchIgnoreCase("[/url]") )
 			return parser.failure(null);
-		String rtn = target==Target.HTML ? "<a href='" + url + "'>" + url + "</a>" : url;
+		Element rtn = new Element("url",url);
 		return parser.success(rtn);
 	}
 
-	private String parseUrl2() {
+	private Element parseUrl2() {
 		parser.begin();
 		if( !parser.matchIgnoreCase("[url=") )
 			return parser.failure(null);
 		String url = parseRealUrl();
 		if( !parser.match(']') )
 			return parser.failure(null);
-		String content = parseWellFormed();
+		Object content = parseWellFormed();
 		if( !parser.matchIgnoreCase("[/url]") )
 			return parser.failure(null);
-		String rtn = target==Target.HTML ? "<a href='" + url + "'>" + content + "</a>" : content;
+		Element rtn = new Element("url",url,content);
 		return parser.success(rtn);
 	}
 
@@ -201,7 +208,7 @@
 		return parser.success(url);
 	}
 
-	private String parseCode() {
+	private Element parseCode() {
 		parser.begin();
 		if( !parser.matchIgnoreCase("[code]") )
 			return parser.failure(null);
@@ -212,22 +219,22 @@
 		}
 		String content = parser.textFrom(start);
 		if( !parser.matchIgnoreCase("[/code]") ) throw new RuntimeException();
-		String rtn = target==Target.HTML ? "<code>"+content+"</code>" : content;
+		Element rtn = new Element("code",content);
 		return parser.success(rtn);
 	}
 
-	private String parseImg() {
+	private Element parseImg() {
 		parser.begin();
 		if( !parser.matchIgnoreCase("[img]") )
 			return parser.failure(null);
 		String url = parseRealUrl();
 		if( !parser.matchIgnoreCase("[/img]") )
 			return parser.failure(null);
-		String rtn = target==Target.HTML ? "<img src='" + url + "'>" : "";
+		Element rtn = new Element("img",url);
 		return parser.success(rtn);
 	}
 
-	private String parseColor() {
+	private Element parseColor() {
 		parser.begin();
 		if( !parser.matchIgnoreCase("[color=") )
 			return parser.failure(null);
@@ -240,14 +247,14 @@
 		String color = parser.textFrom(start);
 		if( !parser.match(']') )
 			return parser.failure(null);
-		String content = parseWellFormed();
+		Object content = parseWellFormed();
 		if( !parser.matchIgnoreCase("[/color]") )
 			return parser.failure(null);
-		String rtn = target==Target.HTML ? "<span style='color: "+color+"'>"+content+"</span>" : content;
+		Element rtn = new Element("color",color,content);
 		return parser.success(rtn);
 	}
 
-	private String parseSize() {
+	private Element parseSize() {
 		parser.begin();
 		if( !parser.matchIgnoreCase("[size=") )
 			return parser.failure(null);
@@ -256,10 +263,10 @@
 		String size = parser.textFrom(start);
 		if( !parser.match(']') )
 			return parser.failure(null);
-		String content = parseWellFormed();
+		Object content = parseWellFormed();
 		if( !parser.matchIgnoreCase("[/size]") )
 			return parser.failure(null);
-		String rtn = target==Target.HTML ? "<span style='font-size: "+size+"em'>"+content+"</span>" : content;
+		Element rtn = new Element("size",size,content);
 		return parser.success(rtn);
 	}
 
@@ -272,55 +279,49 @@
 		return m.find() ? m : null;
 	}
 
-	private String parseVideo() {
+	private Element parseVideo() {
 		parser.begin();
 		if( !parser.matchIgnoreCase("[video]") )
 			return parser.failure(null);
 		String url = parseRealUrl();
 		if( !parser.matchIgnoreCase("[/video]") )
 			return parser.failure(null);
-		if( target==Target.TEXT )
-			return parser.success( "" );
+		Map<String,String> extra = new LinkedHashMap<String,String>();
+		Element rtn = new Element("video",null,url,extra);
 		Matcher m;
 		m = find(youtubePtn1,url);
 		if( m == null )
 			m = find(youtubePtn2,url);
 		if( m != null ) {
-			StringBuilder sb = new StringBuilder();
-			sb.append( "<iframe width='420' height='315' src='https://www.youtube.com/embed/" );
-			sb.append( m.group(1) );
+			extra.put( "site", "youtube" );
+			extra.put( "id", m.group(1) );
 			String t = m.group(2);
-			if( t != null ) {
-				sb.append( "?start=" );
-				sb.append( t );
-			}
-			sb.append( "' frameborder='0' allowfullscreen></iframe>" );
-			return parser.success( sb.toString() );
+			if( t != null )
+				extra.put( "start", t );
+			return parser.success(rtn);
 		}
 		m = find(bitchutePtn,url);
 		if( m != null ) {
-			StringBuilder sb = new StringBuilder();
-			sb.append( "<iframe width='420' height='315' scrolling='no' frameborder='0' style='border: none;' src='https://www.bitchute.com/embed/" );
-			sb.append( m.group(1) );
-			sb.append( "/'></iframe>" );
-			return parser.success( sb.toString() );
+			extra.put( "site", "bitchute" );
+			extra.put( "id", m.group(1) );
+			return parser.success(rtn);
 		}
-		return parser.success( "<a href='" + url + "'>" + url + "</a>" );
+		return parser.success(rtn);
 	}
 
 
-	private String parseQuote1() {
+	private Element parseQuote1() {
 		parser.begin();
 		if( !parser.matchIgnoreCase("[quote]") )
 			return parser.failure(null);
-		String content = parseWellFormed();
+		Object content = parseWellFormed();
 		if( !parser.matchIgnoreCase("[/quote]") )
 			return parser.failure(null);
-		String rtn = quoter.quote(target,content,null);
+		Element rtn = new Element("quote",content);
 		return parser.success(rtn);
 	}
 
-	private String parseQuote2() {
+	private Element parseQuote2() {
 		parser.begin();
 		if( !parser.matchIgnoreCase("[quote=") )
 			return parser.failure(null);
@@ -330,35 +331,11 @@
 		String name = parser.textFrom(start).trim();
 		if( !parser.match(']') )
 			return parser.failure(null);
-		String content = parseWellFormed();
+		Object content = parseWellFormed();
 		if( !parser.matchIgnoreCase("[/quote]") )
 			return parser.failure(null);
-		String rtn = quoter.quote(target,content,name);
+		Element rtn = new Element("quote",name,content);
 		return parser.success(rtn);
 	}
 
-	public static String htmlEncode(String s) {
-		final char[] a = s.toCharArray();
-		StringBuilder buf = new StringBuilder();
-		for( char c : a ) {
-			switch(c) {
-			case '&':
-				buf.append("&amp;");
-				break;
-			case '<':
-				buf.append("&lt;");
-				break;
-			case '>':
-				buf.append("&gt;");
-				break;
-			case '"':
-				buf.append("&quot;");
-				break;
-			default:
-				buf.append(c);
-			}
-		}
-		return buf.toString();
-	}
-
 }
--- a/src/luan/modules/Parsers.luan	Fri Jul 01 15:53:03 2022 -0600
+++ b/src/luan/modules/Parsers.luan	Sun Jul 03 21:59:38 2022 -0600
@@ -9,8 +9,7 @@
 
 local Parsers = {}
 
-Parsers.bbcode_to_html = BBCodeLuan.toHtml
-Parsers.bbcode_to_text = BBCodeLuan.toText
+Parsers.bbcode_parse = BBCodeLuan.parse
 Parsers.csv_to_list = Csv.toList
 Parsers.json_string = BasicLuan.json_string
 Parsers.theme_to_luan = Theme.toLuan
--- a/src/luan/modules/parsers/BBCodeLuan.java	Fri Jul 01 15:53:03 2022 -0600
+++ b/src/luan/modules/parsers/BBCodeLuan.java	Sun Jul 03 21:59:38 2022 -0600
@@ -1,54 +1,56 @@
 package luan.modules.parsers;
 
 import java.util.List;
-import java.util.ArrayList;
-import luan.Luan;
-import luan.LuanFunction;
+import java.util.Map;
+import luan.LuanTable;
 import luan.LuanException;
-import luan.LuanRuntimeException;
 import luan.modules.Utils;
-import luan.modules.HtmlLuan;
 import goodjava.bbcode.BBCode;
 
 
 public final class BBCodeLuan {
 
-	private static BBCode.Quoter quoter(final Luan luan,final LuanFunction quoterFn) {
-		return new BBCode.Quoter() {
-			public String quote(BBCode.Target target,String text,String param) {
-				try {
-					Object obj = quoterFn.call(luan,text,param);
-					if( !(obj instanceof String) )
-						throw new LuanException("BBCode quoter function returned "+Luan.type(obj)+" but string required");
-					return (String)obj;
-				} catch(LuanException e) {
-					throw new LuanRuntimeException(e);
-				}
-			}
-		};
-	}
-
-	public static String toHtml(Luan luan,String text,LuanFunction quoterFn) throws LuanException {
-		return parse(luan,text,quoterFn,BBCode.Target.HTML);
-	}
-
-	public static String toText(Luan luan,String text,LuanFunction quoterFn) throws LuanException {
-		return parse(luan,text,quoterFn,BBCode.Target.TEXT);
-	}
-
-	private static String parse(Luan luan,String text,LuanFunction quoterFn,BBCode.Target target)
+	public static Object parse(String text)
 		throws LuanException
 	{
 		Utils.checkNotNull(text,1);
-		BBCode bbcode = new BBCode(text);
-		bbcode.target = target;
-		if( quoterFn != null )
-			bbcode.quoter = quoter(luan,quoterFn);
-		try {
-			return bbcode.parse();
-		} catch(LuanRuntimeException e) {
-			throw (LuanException)e.getCause();
+		Object obj = BBCode.parse(text);
+		return convert(obj);
+	}
+
+	private static Object convert(Object obj) throws LuanException {
+		if( obj instanceof String )
+			return obj;
+		if( obj instanceof BBCode.Element )
+			return convert((BBCode.Element)obj);
+		if( obj instanceof List )
+			return convert((List)obj);
+		throw new RuntimeException("invalid obj: "+obj);
+	}
+
+	private static LuanTable convert(List list) throws LuanException {
+		LuanTable t = new LuanTable();
+		for( Object obj : list ) {
+			t.rawAdd( convert(obj) );
 		}
+		return t;
+	}
+
+	private static LuanTable convert(BBCode.Element el) throws LuanException {
+		LuanTable t = new LuanTable();
+		t.rawPut( "name", el.name );
+		Object param = el.param;
+		Object contents = el.contents;
+		Map<String,String> extra = el.extra;
+		if( param != null )
+			t.rawPut( "param", param );
+		t.rawPut( "contents", convert(contents) );
+		if( extra != null ) {
+			for( Map.Entry<String,String> entry : extra.entrySet() ) {
+				t.rawPut( entry.getKey(), entry.getValue() );
+			}
+		}
+		return t;
 	}
 
 }