Commit 8c858269 authored by halatmit's avatar halatmit

Add the lookup in pairs list operation to do alist search

Change-Id: Id3473ad588ebd31d5f85082c77c7380256081d02
parent 92ed7964
......@@ -20,6 +20,7 @@
<target name="tests"
depends="BuildServerTests,YailGeneratorTests">
</target>
<!-- =====================================================================
......
......@@ -1547,11 +1547,12 @@ Block name Kawa implementation
- add items to list (yail-list-add-to-list! yail-list . items)
- insert into list (yail-list-insert-item! yail-list index item)
- is in list? (yail-list-member? object yail-list)
- position in list (yail-list-index item list)
- position in list (yail-list-index item list)
- for each (foreach variable bodyform yail-list) [macro] [in control drawer]
- pick random item (yail-list-pick-random yail-list)
- is list? (yail-list? object)
- is empty? (yail-list-empty? yail-list)
- lookup in pairs (yail-alist-lookup key yail-list-of-pairs default)
Lists in App Inventor are implemented as "Yail lists". A Yail list is
a Java pair whose car is a distinguished token
......@@ -1919,6 +1920,44 @@ list, use the make-yail-list constructor with no arguments.
(inexact->exact (floor high)))))
;;; For now, we'll represent tables as lists of pairs.
;;; Note that these are Yail lists, and the implementation
;;; must take account of that. In this implementation, keys and
;;; values can be any blocks objects.
;;; Yail-alist lookup looks up the key in a list of pairs and returns resulting match.
;;; It returns the default if the key is not in the table.
;;; Note that we can't simply use kawa assoc here, because we are
;;; dealing with Yail lists
;;; TODO(hal): Implement dictionaries and
;;; integrate these with get JSON from web services. Probably need to
;;; make new DICTIONARY data type analogous to YailList. Think about
;;; any component operations that need to create dictionaries and whether we
;;; we need a Java class similar to the YailList Java class. Also think about
;;; how to convert dictionaries to strings and how this interacts with printing
;;; JSON objects and whether jsonutils.decode.
(define (yail-alist-lookup key yail-list-of-pairs default)
(android-log
(format #f "List alist lookup key is ~A and table is ~A" key yail-list-of-pairs))
(let loop ((pairs-to-check (yail-list-contents yail-list-of-pairs)))
(cond ((null? pairs-to-check) default)
((not (pair-ok? (car pairs-to-check)))
(signal-runtime-error
(format #f "Lookup in pairs: the list ~A is not a well-formed list of pairs"
(get-display-representation yail-list-of-pairs))
"Invalid list of pairs"))
((equal? key (car (yail-list-contents (car pairs-to-check))))
(cadr (yail-list-contents (car pairs-to-check))))
(else (loop (cdr pairs-to-check))))))
(define (pair-ok? candidate-pair)
(and (yail-list? candidate-pair)
(= (length (yail-list-contents candidate-pair)) 2)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;; End of List implementation
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
......
......@@ -736,6 +736,57 @@ public class YailEvalTest extends TestCase {
}
}
/* a-list lookup */
public void testAListLookup1() throws Throwable {
String schemeInputString = "(begin " +
"(define pair1 (make-yail-list \"a\" \"b\")) " +
"(define pair2 (make-yail-list \"aa\" \"bb\")) " +
"(define pairs (make-yail-list pair1 pair2)) " +
"(yail-alist-lookup \"aa\" pairs \"nothing\") " +
")";
String schemeResultString = "bb";
assertEquals(schemeResultString, scheme.eval(schemeInputString).toString());
}
public void testAListLookup2() throws Throwable {
String schemeInputString = "(begin " +
"(define pair1 (make-yail-list \"a\" \"b\")) " +
"(define pair2 (make-yail-list (make-yail-list 1 2) \"bb\")) " +
"(define pairs (make-yail-list pair1 pair2)) " +
"(yail-alist-lookup (make-yail-list 1 (+ 1 1)) pairs \"nothing\") " +
")";
String schemeResultString = "bb";
assertEquals(schemeResultString, scheme.eval(schemeInputString).toString());
}
public void testAListLookup3() throws Throwable {
String schemeInputString = "(begin " +
"(define pair1 (make-yail-list \"a\" \"b\")) " +
"(define pair2 (make-yail-list (make-yail-list 1 2) \"bb\")) " +
"(define pairs (make-yail-list pair1 pair2)) " +
"(yail-alist-lookup (make-yail-list \"foo\" (+ 1 1)) pairs \"nothing\") " +
")";
String schemeResultString = "nothing";
assertEquals(schemeResultString, scheme.eval(schemeInputString).toString());
}
public void testAListLookup4() throws Throwable {
/* check that this signals a runtime error for a bad pair */
String schemeInnerInputString = "(begin " +
"(define pair1 (make-yail-list \"a\" \"b\")) " +
"(define pair2 (make-yail-list (make-yail-list 1 2) \"bb\")) " +
"(define badpair 100) " +
"(define pairs (make-yail-list pair1 pair2 badpair)) " +
"(yail-alist-lookup (make-yail-list \"foo\" (+ 1 1)) pairs \"nothing\") " +
")";
String schemeInputString = "(try-catch " +
schemeInnerInputString +
" (exception com.google.appinventor.components.runtime.errors.YailRuntimeError " +
" \"bad pair\" " +
"))";
assertEquals("bad pair", scheme.eval(thunkify(schemeInputString)).toString());
}
public void testListInsertionMiddle() throws Throwable {
/* test list insertion in middle */
String schemeInputString = "(begin " +
......
......@@ -595,6 +595,9 @@ public class Web extends AndroidNonvisibleComponent implements Component {
// The object will be sanitized to produce the corresponding Yail data by call-component-method.
// That mechanism would need to be extended if we ever change JSON decoding to produce
// dictionaries rather than lists
// TOOD(hal): Provide an alternative way to decode JSON objects to dictionaries. Maybe with
// renaming this JsonTextDecodeWithPairs and making JsonTextDecode the one to use
// dictionaries
public Object JsonTextDecode(String jsonText) {
try {
return decodeJsonText(jsonText);
......
......@@ -82,6 +82,8 @@ public class JsonUtil {
* @throws JSONException if an element in jObject cannot be
* converted properly.
*/
// TODO(hal): If we implement dictionaries, we'll need to decode Json
// objects to dictionaires instead.
public static List<Object> getListFromJsonObject(JSONObject jObject) throws JSONException {
List<Object> returnList = new ArrayList<Object>();
Iterator<String> keys = jObject.keys();
......
......@@ -158,6 +158,8 @@
<BlockGenusMember>list-to-csv-table</BlockGenusMember>
<BlockGenusMember>list-from-csv-row</BlockGenusMember>
<BlockGenusMember>list-from-csv-table</BlockGenusMember>
<BlockGenusMember>list-lookup-in-pairs</BlockGenusMember>
</BlockDrawer>
<BlockDrawer name="Math" button-color="math">
......
......@@ -2058,6 +2058,35 @@ For multiple screen apps, use close screen with value rather than close screen w
</LangSpecProperties>
</BlockGenus>
<!-- List Lookup in Pairs Block -->
<BlockGenus name="list-lookup-in-pairs" decorator="call" kind="function" initlabel="lookup in pairs " color="list">
<description>
<arg-description n="1" name="key" doc-name="key">The key to look up </arg-description>
<arg-description n="2" name="pairs" doc-name="pairs">A list of (key value) pairs</arg-description>
<arg-description n="3" name="notFound"
doc-name="notFound">Value to return if there is no pair with the given key.</arg-description>
<text>Returns the value associated with the key in the list of pairs.</text>
</description>
<BlockConnectors>
<BlockConnector label="" connector-kind="plug" connector-type="poly"/>
<BlockConnector label="key" connector-kind="socket" connector-type="poly"/>
<BlockConnector label="pairs" connector-kind="socket" connector-type="poly"/>
<BlockConnector label="notFound" connector-kind="socket" connector-type="poly">
<DefaultArg genus-name="text" label="NotFound"/>
</BlockConnector>
</BlockConnectors>
<LangSpecProperties>
<LangSpecProperty key="ya-kind" value="primitive"/>
<LangSpecProperty key="ya-rep" value="yail-alist-lookup"/>
<LangSpecProperty key="type-exclude-1" value="argument"/>
<LangSpecProperty key="socket-exclude-1" value="key/argument"/>
<LangSpecProperty key="socket-allow-1" value="pairs/value"/>
<LangSpecProperty key="socket-allow-2" value="pairs/list"/>
<LangSpecProperty key="socket-allow-3" value="notFound/text"/>
<LangSpecProperty key="socket-allow-4" value="notFound/text"/>
</LangSpecProperties>
</BlockGenus>
<!-- Math -->
<!-- Greaterthan Block -->
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment